OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [gensupport.c] - Blame information for rev 333

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

Line No. Rev Author Line
1 280 jeremybenn
/* Support routines for the various generation passes.
2
   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
3
   2010, Free Software Foundation, Inc.
4
 
5
   This file is part of GCC.
6
 
7
   GCC is free software; you can redistribute it and/or modify it
8
   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
   GCC is distributed in the hope that it will be useful, but WITHOUT
13
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15
   License for more details.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with GCC; see the file COPYING3.  If not see
19
   <http://www.gnu.org/licenses/>.  */
20
 
21
#include "bconfig.h"
22
#include "system.h"
23
#include "coretypes.h"
24
#include "tm.h"
25
#include "rtl.h"
26
#include "obstack.h"
27
#include "errors.h"
28
#include "hashtab.h"
29
#include "gensupport.h"
30
 
31
 
32
/* In case some macros used by files we include need it, define this here.  */
33
int target_flags;
34
 
35
int insn_elision = 1;
36
 
37
const char *in_fname;
38
 
39
/* This callback will be invoked whenever an rtl include directive is
40
   processed.  To be used for creation of the dependency file.  */
41
void (*include_callback) (const char *);
42
 
43
static struct obstack obstack;
44
struct obstack *rtl_obstack = &obstack;
45
 
46
static int sequence_num;
47
static int errors;
48
 
49
static int predicable_default;
50
static const char *predicable_true;
51
static const char *predicable_false;
52
 
53
static htab_t condition_table;
54
 
55
static char *base_dir = NULL;
56
 
57
/* We initially queue all patterns, process the define_insn and
58
   define_cond_exec patterns, then return them one at a time.  */
59
 
60
struct queue_elem
61
{
62
  rtx data;
63
  const char *filename;
64
  int lineno;
65
  struct queue_elem *next;
66
  /* In a DEFINE_INSN that came from a DEFINE_INSN_AND_SPLIT, SPLIT
67
     points to the generated DEFINE_SPLIT.  */
68
  struct queue_elem *split;
69
};
70
 
71
static struct queue_elem *define_attr_queue;
72
static struct queue_elem **define_attr_tail = &define_attr_queue;
73
static struct queue_elem *define_pred_queue;
74
static struct queue_elem **define_pred_tail = &define_pred_queue;
75
static struct queue_elem *define_insn_queue;
76
static struct queue_elem **define_insn_tail = &define_insn_queue;
77
static struct queue_elem *define_cond_exec_queue;
78
static struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue;
79
static struct queue_elem *other_queue;
80
static struct queue_elem **other_tail = &other_queue;
81
 
82
static struct queue_elem *queue_pattern (rtx, struct queue_elem ***,
83
                                         const char *, int);
84
 
85
/* Current maximum length of directory names in the search path
86
   for include files.  (Altered as we get more of them.)  */
87
 
88
size_t max_include_len;
89
 
90
struct file_name_list
91
  {
92
    struct file_name_list *next;
93
    const char *fname;
94
  };
95
 
96
struct file_name_list *first_dir_md_include = 0;  /* First dir to search */
97
        /* First dir to search for <file> */
98
struct file_name_list *first_bracket_include = 0;
99
struct file_name_list *last_dir_md_include = 0;        /* Last in chain */
100
 
101
static void remove_constraints (rtx);
102
static void process_rtx (rtx, int);
103
 
104
static int is_predicable (struct queue_elem *);
105
static void identify_predicable_attribute (void);
106
static int n_alternatives (const char *);
107
static void collect_insn_data (rtx, int *, int *);
108
static rtx alter_predicate_for_insn (rtx, int, int, int);
109
static const char *alter_test_for_insn (struct queue_elem *,
110
                                        struct queue_elem *);
111
static char *shift_output_template (char *, const char *, int);
112
static const char *alter_output_for_insn (struct queue_elem *,
113
                                          struct queue_elem *,
114
                                          int, int);
115
static void process_one_cond_exec (struct queue_elem *);
116
static void process_define_cond_exec (void);
117
static void process_include (rtx, int);
118
static char *save_string (const char *, int);
119
static void init_predicate_table (void);
120
static void record_insn_name (int, const char *);
121
 
122
void
123
message_with_line (int lineno, const char *msg, ...)
124
{
125
  va_list ap;
126
 
127
  va_start (ap, msg);
128
 
129
  fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno);
130
  vfprintf (stderr, msg, ap);
131
  fputc ('\n', stderr);
132
 
133
  va_end (ap);
134
}
135
 
136
/* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in
137
   the gensupport programs.  */
138
 
139
rtx
140
gen_rtx_CONST_INT (enum machine_mode ARG_UNUSED (mode),
141
                   HOST_WIDE_INT arg)
142
{
143
  rtx rt = rtx_alloc (CONST_INT);
144
 
145
  XWINT (rt, 0) = arg;
146
  return rt;
147
}
148
 
149
/* Queue PATTERN on LIST_TAIL.  Return the address of the new queue
150
   element.  */
151
 
152
static struct queue_elem *
153
queue_pattern (rtx pattern, struct queue_elem ***list_tail,
154
               const char *filename, int lineno)
155
{
156
  struct queue_elem *e = XNEW(struct queue_elem);
157
  e->data = pattern;
158
  e->filename = filename;
159
  e->lineno = lineno;
160
  e->next = NULL;
161
  e->split = NULL;
162
  **list_tail = e;
163
  *list_tail = &e->next;
164
  return e;
165
}
166
 
167
/* Recursively remove constraints from an rtx.  */
168
 
169
static void
170
remove_constraints (rtx part)
171
{
172
  int i, j;
173
  const char *format_ptr;
174
 
175
  if (part == 0)
176
    return;
177
 
178
  if (GET_CODE (part) == MATCH_OPERAND)
179
    XSTR (part, 2) = "";
180
  else if (GET_CODE (part) == MATCH_SCRATCH)
181
    XSTR (part, 1) = "";
182
 
183
  format_ptr = GET_RTX_FORMAT (GET_CODE (part));
184
 
185
  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
186
    switch (*format_ptr++)
187
      {
188
      case 'e':
189
      case 'u':
190
        remove_constraints (XEXP (part, i));
191
        break;
192
      case 'E':
193
        if (XVEC (part, i) != NULL)
194
          for (j = 0; j < XVECLEN (part, i); j++)
195
            remove_constraints (XVECEXP (part, i, j));
196
        break;
197
      }
198
}
199
 
200
/* Process an include file assuming that it lives in gcc/config/{target}/
201
   if the include looks like (include "file").  */
202
 
203
static void
204
process_include (rtx desc, int lineno)
205
{
206
  const char *filename = XSTR (desc, 0);
207
  const char *old_filename;
208
  int old_lineno;
209
  char *pathname;
210
  FILE *input_file;
211
 
212
  /* If specified file name is absolute, skip the include stack.  */
213
  if (! IS_ABSOLUTE_PATH (filename))
214
    {
215
      struct file_name_list *stackp;
216
 
217
      /* Search directory path, trying to open the file.  */
218
      for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
219
        {
220
          static const char sep[2] = { DIR_SEPARATOR, '\0' };
221
 
222
          pathname = concat (stackp->fname, sep, filename, NULL);
223
          input_file = fopen (pathname, "r");
224
          if (input_file != NULL)
225
            goto success;
226
          free (pathname);
227
        }
228
    }
229
 
230
  if (base_dir)
231
    pathname = concat (base_dir, filename, NULL);
232
  else
233
    pathname = xstrdup (filename);
234
  input_file = fopen (pathname, "r");
235
  if (input_file == NULL)
236
    {
237
      free (pathname);
238
      message_with_line (lineno, "include file `%s' not found", filename);
239
      errors = 1;
240
      return;
241
    }
242
 success:
243
 
244
  /* Save old cursor; setup new for the new file.  Note that "lineno" the
245
     argument to this function is the beginning of the include statement,
246
     while read_rtx_lineno has already been advanced.  */
247
  old_filename = read_rtx_filename;
248
  old_lineno = read_rtx_lineno;
249
  read_rtx_filename = pathname;
250
  read_rtx_lineno = 1;
251
 
252
  if (include_callback)
253
    include_callback (pathname);
254
 
255
  /* Read the entire file.  */
256
  while (read_rtx (input_file, &desc, &lineno))
257
    process_rtx (desc, lineno);
258
 
259
  /* Do not free pathname.  It is attached to the various rtx queue
260
     elements.  */
261
 
262
  read_rtx_filename = old_filename;
263
  read_rtx_lineno = old_lineno;
264
 
265
  fclose (input_file);
266
}
267
 
268
/* Process a top level rtx in some way, queuing as appropriate.  */
269
 
270
static void
271
process_rtx (rtx desc, int lineno)
272
{
273
  switch (GET_CODE (desc))
274
    {
275
    case DEFINE_INSN:
276
      queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno);
277
      break;
278
 
279
    case DEFINE_COND_EXEC:
280
      queue_pattern (desc, &define_cond_exec_tail, read_rtx_filename, lineno);
281
      break;
282
 
283
    case DEFINE_ATTR:
284
      queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno);
285
      break;
286
 
287
    case DEFINE_PREDICATE:
288
    case DEFINE_SPECIAL_PREDICATE:
289
    case DEFINE_CONSTRAINT:
290
    case DEFINE_REGISTER_CONSTRAINT:
291
    case DEFINE_MEMORY_CONSTRAINT:
292
    case DEFINE_ADDRESS_CONSTRAINT:
293
      queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno);
294
      break;
295
 
296
    case INCLUDE:
297
      process_include (desc, lineno);
298
      break;
299
 
300
    case DEFINE_INSN_AND_SPLIT:
301
      {
302
        const char *split_cond;
303
        rtx split;
304
        rtvec attr;
305
        int i;
306
        struct queue_elem *insn_elem;
307
        struct queue_elem *split_elem;
308
 
309
        /* Create a split with values from the insn_and_split.  */
310
        split = rtx_alloc (DEFINE_SPLIT);
311
 
312
        i = XVECLEN (desc, 1);
313
        XVEC (split, 0) = rtvec_alloc (i);
314
        while (--i >= 0)
315
          {
316
            XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i));
317
            remove_constraints (XVECEXP (split, 0, i));
318
          }
319
 
320
        /* If the split condition starts with "&&", append it to the
321
           insn condition to create the new split condition.  */
322
        split_cond = XSTR (desc, 4);
323
        if (split_cond[0] == '&' && split_cond[1] == '&')
324
          {
325
            copy_rtx_ptr_loc (split_cond + 2, split_cond);
326
            split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2);
327
          }
328
        XSTR (split, 1) = split_cond;
329
        XVEC (split, 2) = XVEC (desc, 5);
330
        XSTR (split, 3) = XSTR (desc, 6);
331
 
332
        /* Fix up the DEFINE_INSN.  */
333
        attr = XVEC (desc, 7);
334
        PUT_CODE (desc, DEFINE_INSN);
335
        XVEC (desc, 4) = attr;
336
 
337
        /* Queue them.  */
338
        insn_elem
339
          = queue_pattern (desc, &define_insn_tail, read_rtx_filename,
340
                           lineno);
341
        split_elem
342
          = queue_pattern (split, &other_tail, read_rtx_filename, lineno);
343
        insn_elem->split = split_elem;
344
        break;
345
      }
346
 
347
    default:
348
      queue_pattern (desc, &other_tail, read_rtx_filename, lineno);
349
      break;
350
    }
351
}
352
 
353
/* Return true if attribute PREDICABLE is true for ELEM, which holds
354
   a DEFINE_INSN.  */
355
 
356
static int
357
is_predicable (struct queue_elem *elem)
358
{
359
  rtvec vec = XVEC (elem->data, 4);
360
  const char *value;
361
  int i;
362
 
363
  if (! vec)
364
    return predicable_default;
365
 
366
  for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i)
367
    {
368
      rtx sub = RTVEC_ELT (vec, i);
369
      switch (GET_CODE (sub))
370
        {
371
        case SET_ATTR:
372
          if (strcmp (XSTR (sub, 0), "predicable") == 0)
373
            {
374
              value = XSTR (sub, 1);
375
              goto found;
376
            }
377
          break;
378
 
379
        case SET_ATTR_ALTERNATIVE:
380
          if (strcmp (XSTR (sub, 0), "predicable") == 0)
381
            {
382
              message_with_line (elem->lineno,
383
                                 "multiple alternatives for `predicable'");
384
              errors = 1;
385
              return 0;
386
            }
387
          break;
388
 
389
        case SET:
390
          if (GET_CODE (SET_DEST (sub)) != ATTR
391
              || strcmp (XSTR (SET_DEST (sub), 0), "predicable") != 0)
392
            break;
393
          sub = SET_SRC (sub);
394
          if (GET_CODE (sub) == CONST_STRING)
395
            {
396
              value = XSTR (sub, 0);
397
              goto found;
398
            }
399
 
400
          /* ??? It would be possible to handle this if we really tried.
401
             It's not easy though, and I'm not going to bother until it
402
             really proves necessary.  */
403
          message_with_line (elem->lineno,
404
                             "non-constant value for `predicable'");
405
          errors = 1;
406
          return 0;
407
 
408
        default:
409
          gcc_unreachable ();
410
        }
411
    }
412
 
413
  return predicable_default;
414
 
415
 found:
416
  /* Verify that predicability does not vary on the alternative.  */
417
  /* ??? It should be possible to handle this by simply eliminating
418
     the non-predicable alternatives from the insn.  FRV would like
419
     to do this.  Delay this until we've got the basics solid.  */
420
  if (strchr (value, ',') != NULL)
421
    {
422
      message_with_line (elem->lineno,
423
                         "multiple alternatives for `predicable'");
424
      errors = 1;
425
      return 0;
426
    }
427
 
428
  /* Find out which value we're looking at.  */
429
  if (strcmp (value, predicable_true) == 0)
430
    return 1;
431
  if (strcmp (value, predicable_false) == 0)
432
    return 0;
433
 
434
  message_with_line (elem->lineno,
435
                     "unknown value `%s' for `predicable' attribute",
436
                     value);
437
  errors = 1;
438
  return 0;
439
}
440
 
441
/* Examine the attribute "predicable"; discover its boolean values
442
   and its default.  */
443
 
444
static void
445
identify_predicable_attribute (void)
446
{
447
  struct queue_elem *elem;
448
  char *p_true, *p_false;
449
  const char *value;
450
 
451
  /* Look for the DEFINE_ATTR for `predicable', which must exist.  */
452
  for (elem = define_attr_queue; elem ; elem = elem->next)
453
    if (strcmp (XSTR (elem->data, 0), "predicable") == 0)
454
      goto found;
455
 
456
  message_with_line (define_cond_exec_queue->lineno,
457
                     "attribute `predicable' not defined");
458
  errors = 1;
459
  return;
460
 
461
 found:
462
  value = XSTR (elem->data, 1);
463
  p_false = xstrdup (value);
464
  p_true = strchr (p_false, ',');
465
  if (p_true == NULL || strchr (++p_true, ',') != NULL)
466
    {
467
      message_with_line (elem->lineno,
468
                         "attribute `predicable' is not a boolean");
469
      errors = 1;
470
      if (p_false)
471
        free (p_false);
472
      return;
473
    }
474
  p_true[-1] = '\0';
475
 
476
  predicable_true = p_true;
477
  predicable_false = p_false;
478
 
479
  switch (GET_CODE (XEXP (elem->data, 2)))
480
    {
481
    case CONST_STRING:
482
      value = XSTR (XEXP (elem->data, 2), 0);
483
      break;
484
 
485
    case CONST:
486
      message_with_line (elem->lineno,
487
                         "attribute `predicable' cannot be const");
488
      errors = 1;
489
      if (p_false)
490
        free (p_false);
491
      return;
492
 
493
    default:
494
      message_with_line (elem->lineno,
495
                         "attribute `predicable' must have a constant default");
496
      errors = 1;
497
      if (p_false)
498
        free (p_false);
499
      return;
500
    }
501
 
502
  if (strcmp (value, p_true) == 0)
503
    predicable_default = 1;
504
  else if (strcmp (value, p_false) == 0)
505
    predicable_default = 0;
506
  else
507
    {
508
      message_with_line (elem->lineno,
509
                         "unknown value `%s' for `predicable' attribute",
510
                         value);
511
      errors = 1;
512
      if (p_false)
513
        free (p_false);
514
    }
515
}
516
 
517
/* Return the number of alternatives in constraint S.  */
518
 
519
static int
520
n_alternatives (const char *s)
521
{
522
  int n = 1;
523
 
524
  if (s)
525
    while (*s)
526
      n += (*s++ == ',');
527
 
528
  return n;
529
}
530
 
531
/* Determine how many alternatives there are in INSN, and how many
532
   operands.  */
533
 
534
static void
535
collect_insn_data (rtx pattern, int *palt, int *pmax)
536
{
537
  const char *fmt;
538
  enum rtx_code code;
539
  int i, j, len;
540
 
541
  code = GET_CODE (pattern);
542
  switch (code)
543
    {
544
    case MATCH_OPERAND:
545
      i = n_alternatives (XSTR (pattern, 2));
546
      *palt = (i > *palt ? i : *palt);
547
      /* Fall through.  */
548
 
549
    case MATCH_OPERATOR:
550
    case MATCH_SCRATCH:
551
    case MATCH_PARALLEL:
552
      i = XINT (pattern, 0);
553
      if (i > *pmax)
554
        *pmax = i;
555
      break;
556
 
557
    default:
558
      break;
559
    }
560
 
561
  fmt = GET_RTX_FORMAT (code);
562
  len = GET_RTX_LENGTH (code);
563
  for (i = 0; i < len; i++)
564
    {
565
      switch (fmt[i])
566
        {
567
        case 'e': case 'u':
568
          collect_insn_data (XEXP (pattern, i), palt, pmax);
569
          break;
570
 
571
        case 'V':
572
          if (XVEC (pattern, i) == NULL)
573
            break;
574
          /* Fall through.  */
575
        case 'E':
576
          for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
577
            collect_insn_data (XVECEXP (pattern, i, j), palt, pmax);
578
          break;
579
 
580
        case 'i': case 'w': case '0': case 's': case 'S': case 'T':
581
          break;
582
 
583
        default:
584
          gcc_unreachable ();
585
        }
586
    }
587
}
588
 
589
static rtx
590
alter_predicate_for_insn (rtx pattern, int alt, int max_op, int lineno)
591
{
592
  const char *fmt;
593
  enum rtx_code code;
594
  int i, j, len;
595
 
596
  code = GET_CODE (pattern);
597
  switch (code)
598
    {
599
    case MATCH_OPERAND:
600
      {
601
        const char *c = XSTR (pattern, 2);
602
 
603
        if (n_alternatives (c) != 1)
604
          {
605
            message_with_line (lineno,
606
                               "too many alternatives for operand %d",
607
                               XINT (pattern, 0));
608
            errors = 1;
609
            return NULL;
610
          }
611
 
612
        /* Replicate C as needed to fill out ALT alternatives.  */
613
        if (c && *c && alt > 1)
614
          {
615
            size_t c_len = strlen (c);
616
            size_t len = alt * (c_len + 1);
617
            char *new_c = XNEWVEC(char, len);
618
 
619
            memcpy (new_c, c, c_len);
620
            for (i = 1; i < alt; ++i)
621
              {
622
                new_c[i * (c_len + 1) - 1] = ',';
623
                memcpy (&new_c[i * (c_len + 1)], c, c_len);
624
              }
625
            new_c[len - 1] = '\0';
626
            XSTR (pattern, 2) = new_c;
627
          }
628
      }
629
      /* Fall through.  */
630
 
631
    case MATCH_OPERATOR:
632
    case MATCH_SCRATCH:
633
    case MATCH_PARALLEL:
634
      XINT (pattern, 0) += max_op;
635
      break;
636
 
637
    default:
638
      break;
639
    }
640
 
641
  fmt = GET_RTX_FORMAT (code);
642
  len = GET_RTX_LENGTH (code);
643
  for (i = 0; i < len; i++)
644
    {
645
      rtx r;
646
 
647
      switch (fmt[i])
648
        {
649
        case 'e': case 'u':
650
          r = alter_predicate_for_insn (XEXP (pattern, i), alt,
651
                                        max_op, lineno);
652
          if (r == NULL)
653
            return r;
654
          break;
655
 
656
        case 'E':
657
          for (j = XVECLEN (pattern, i) - 1; j >= 0; --j)
658
            {
659
              r = alter_predicate_for_insn (XVECEXP (pattern, i, j),
660
                                            alt, max_op, lineno);
661
              if (r == NULL)
662
                return r;
663
            }
664
          break;
665
 
666
        case 'i': case 'w': case '0': case 's':
667
          break;
668
 
669
        default:
670
          gcc_unreachable ();
671
        }
672
    }
673
 
674
  return pattern;
675
}
676
 
677
static const char *
678
alter_test_for_insn (struct queue_elem *ce_elem,
679
                     struct queue_elem *insn_elem)
680
{
681
  return join_c_conditions (XSTR (ce_elem->data, 1),
682
                            XSTR (insn_elem->data, 2));
683
}
684
 
685
/* Adjust all of the operand numbers in SRC to match the shift they'll
686
   get from an operand displacement of DISP.  Return a pointer after the
687
   adjusted string.  */
688
 
689
static char *
690
shift_output_template (char *dest, const char *src, int disp)
691
{
692
  while (*src)
693
    {
694
      char c = *src++;
695
      *dest++ = c;
696
      if (c == '%')
697
        {
698
          c = *src++;
699
          if (ISDIGIT ((unsigned char) c))
700
            c += disp;
701
          else if (ISALPHA (c))
702
            {
703
              *dest++ = c;
704
              c = *src++ + disp;
705
            }
706
          *dest++ = c;
707
        }
708
    }
709
 
710
  return dest;
711
}
712
 
713
static const char *
714
alter_output_for_insn (struct queue_elem *ce_elem,
715
                       struct queue_elem *insn_elem,
716
                       int alt, int max_op)
717
{
718
  const char *ce_out, *insn_out;
719
  char *result, *p;
720
  size_t len, ce_len, insn_len;
721
 
722
  /* ??? Could coordinate with genoutput to not duplicate code here.  */
723
 
724
  ce_out = XSTR (ce_elem->data, 2);
725
  insn_out = XTMPL (insn_elem->data, 3);
726
  if (!ce_out || *ce_out == '\0')
727
    return insn_out;
728
 
729
  ce_len = strlen (ce_out);
730
  insn_len = strlen (insn_out);
731
 
732
  if (*insn_out == '*')
733
    /* You must take care of the predicate yourself.  */
734
    return insn_out;
735
 
736
  if (*insn_out == '@')
737
    {
738
      len = (ce_len + 1) * alt + insn_len + 1;
739
      p = result = XNEWVEC(char, len);
740
 
741
      do
742
        {
743
          do
744
            *p++ = *insn_out++;
745
          while (ISSPACE ((unsigned char) *insn_out));
746
 
747
          if (*insn_out != '#')
748
            {
749
              p = shift_output_template (p, ce_out, max_op);
750
              *p++ = ' ';
751
            }
752
 
753
          do
754
            *p++ = *insn_out++;
755
          while (*insn_out && *insn_out != '\n');
756
        }
757
      while (*insn_out);
758
      *p = '\0';
759
    }
760
  else
761
    {
762
      len = ce_len + 1 + insn_len + 1;
763
      result = XNEWVEC (char, len);
764
 
765
      p = shift_output_template (result, ce_out, max_op);
766
      *p++ = ' ';
767
      memcpy (p, insn_out, insn_len + 1);
768
    }
769
 
770
  return result;
771
}
772
 
773
/* Replicate insns as appropriate for the given DEFINE_COND_EXEC.  */
774
 
775
static void
776
process_one_cond_exec (struct queue_elem *ce_elem)
777
{
778
  struct queue_elem *insn_elem;
779
  for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next)
780
    {
781
      int alternatives, max_operand;
782
      rtx pred, insn, pattern, split;
783
      char *new_name;
784
      int i;
785
 
786
      if (! is_predicable (insn_elem))
787
        continue;
788
 
789
      alternatives = 1;
790
      max_operand = -1;
791
      collect_insn_data (insn_elem->data, &alternatives, &max_operand);
792
      max_operand += 1;
793
 
794
      if (XVECLEN (ce_elem->data, 0) != 1)
795
        {
796
          message_with_line (ce_elem->lineno,
797
                             "too many patterns in predicate");
798
          errors = 1;
799
          return;
800
        }
801
 
802
      pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0));
803
      pred = alter_predicate_for_insn (pred, alternatives, max_operand,
804
                                       ce_elem->lineno);
805
      if (pred == NULL)
806
        return;
807
 
808
      /* Construct a new pattern for the new insn.  */
809
      insn = copy_rtx (insn_elem->data);
810
      new_name = XNEWVAR (char, strlen XSTR (insn_elem->data, 0) + 4);
811
      sprintf (new_name, "*p %s", XSTR (insn_elem->data, 0));
812
      XSTR (insn, 0) = new_name;
813
      pattern = rtx_alloc (COND_EXEC);
814
      XEXP (pattern, 0) = pred;
815
      if (XVECLEN (insn, 1) == 1)
816
        {
817
          XEXP (pattern, 1) = XVECEXP (insn, 1, 0);
818
          XVECEXP (insn, 1, 0) = pattern;
819
          PUT_NUM_ELEM (XVEC (insn, 1), 1);
820
        }
821
      else
822
        {
823
          XEXP (pattern, 1) = rtx_alloc (PARALLEL);
824
          XVEC (XEXP (pattern, 1), 0) = XVEC (insn, 1);
825
          XVEC (insn, 1) = rtvec_alloc (1);
826
          XVECEXP (insn, 1, 0) = pattern;
827
        }
828
 
829
      XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem);
830
      XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem,
831
                                              alternatives, max_operand);
832
 
833
      /* ??? Set `predicable' to false.  Not crucial since it's really
834
         only used here, and we won't reprocess this new pattern.  */
835
 
836
      /* Put the new pattern on the `other' list so that it
837
         (a) is not reprocessed by other define_cond_exec patterns
838
         (b) appears after all normal define_insn patterns.
839
 
840
         ??? B is debatable.  If one has normal insns that match
841
         cond_exec patterns, they will be preferred over these
842
         generated patterns.  Whether this matters in practice, or if
843
         it's a good thing, or whether we should thread these new
844
         patterns into the define_insn chain just after their generator
845
         is something we'll have to experiment with.  */
846
 
847
      queue_pattern (insn, &other_tail, insn_elem->filename,
848
                     insn_elem->lineno);
849
 
850
      if (!insn_elem->split)
851
        continue;
852
 
853
      /* If the original insn came from a define_insn_and_split,
854
         generate a new split to handle the predicated insn.  */
855
      split = copy_rtx (insn_elem->split->data);
856
      /* Predicate the pattern matched by the split.  */
857
      pattern = rtx_alloc (COND_EXEC);
858
      XEXP (pattern, 0) = pred;
859
      if (XVECLEN (split, 0) == 1)
860
        {
861
          XEXP (pattern, 1) = XVECEXP (split, 0, 0);
862
          XVECEXP (split, 0, 0) = pattern;
863
          PUT_NUM_ELEM (XVEC (split, 0), 1);
864
        }
865
      else
866
        {
867
          XEXP (pattern, 1) = rtx_alloc (PARALLEL);
868
          XVEC (XEXP (pattern, 1), 0) = XVEC (split, 0);
869
          XVEC (split, 0) = rtvec_alloc (1);
870
          XVECEXP (split, 0, 0) = pattern;
871
        }
872
      /* Predicate all of the insns generated by the split.  */
873
      for (i = 0; i < XVECLEN (split, 2); i++)
874
        {
875
          pattern = rtx_alloc (COND_EXEC);
876
          XEXP (pattern, 0) = pred;
877
          XEXP (pattern, 1) = XVECEXP (split, 2, i);
878
          XVECEXP (split, 2, i) = pattern;
879
        }
880
      /* Add the new split to the queue.  */
881
      queue_pattern (split, &other_tail, read_rtx_filename,
882
                     insn_elem->split->lineno);
883
    }
884
}
885
 
886
/* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN
887
   patterns appropriately.  */
888
 
889
static void
890
process_define_cond_exec (void)
891
{
892
  struct queue_elem *elem;
893
 
894
  identify_predicable_attribute ();
895
  if (errors)
896
    return;
897
 
898
  for (elem = define_cond_exec_queue; elem ; elem = elem->next)
899
    process_one_cond_exec (elem);
900
}
901
 
902
static char *
903
save_string (const char *s, int len)
904
{
905
  char *result = XNEWVEC (char, len + 1);
906
 
907
  memcpy (result, s, len);
908
  result[len] = 0;
909
  return result;
910
}
911
 
912
 
913
/* The entry point for initializing the reader.  */
914
 
915
int
916
init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *))
917
{
918
  FILE *input_file;
919
  int c, i, lineno;
920
  char *lastsl;
921
  rtx desc;
922
  bool no_more_options;
923
  bool already_read_stdin;
924
 
925
  /* Unlock the stdio streams.  */
926
  unlock_std_streams ();
927
 
928
  /* First we loop over all the options.  */
929
  for (i = 1; i < argc; i++)
930
    {
931
      if (argv[i][0] != '-')
932
        continue;
933
 
934
      c = argv[i][1];
935
      switch (c)
936
        {
937
        case 'I':               /* Add directory to path for includes.  */
938
          {
939
            struct file_name_list *dirtmp;
940
 
941
            dirtmp = XNEW (struct file_name_list);
942
            dirtmp->next = 0;    /* New one goes on the end */
943
            if (first_dir_md_include == 0)
944
              first_dir_md_include = dirtmp;
945
            else
946
              last_dir_md_include->next = dirtmp;
947
            last_dir_md_include = dirtmp;       /* Tail follows the last one */
948
            if (argv[i][1] == 'I' && argv[i][2] != 0)
949
              dirtmp->fname = argv[i] + 2;
950
            else if (i + 1 == argc)
951
              fatal ("directory name missing after -I option");
952
            else
953
              dirtmp->fname = argv[++i];
954
            if (strlen (dirtmp->fname) > max_include_len)
955
              max_include_len = strlen (dirtmp->fname);
956
          }
957
          break;
958
 
959
        case '\0':
960
          /* An argument consisting of exactly one dash is a request to
961
             read stdin.  This will be handled in the second loop.  */
962
          continue;
963
 
964
        case '-':
965
          /* An argument consisting of just two dashes causes option
966
             parsing to cease.  */
967
          if (argv[i][2] == '\0')
968
            goto stop_parsing_options;
969
 
970
        default:
971
          /* The program may have provided a callback so it can
972
             accept its own options.  */
973
          if (parse_opt && parse_opt (argv[i]))
974
            break;
975
 
976
          fatal ("invalid option `%s'", argv[i]);
977
        }
978
    }
979
 
980
 stop_parsing_options:
981
 
982
  /* Prepare to read input.  */
983
  condition_table = htab_create (500, hash_c_test, cmp_c_test, NULL);
984
  init_predicate_table ();
985
  obstack_init (rtl_obstack);
986
  errors = 0;
987
  sequence_num = 0;
988
  no_more_options = false;
989
  already_read_stdin = false;
990
 
991
 
992
  /* Now loop over all input files.  */
993
  for (i = 1; i < argc; i++)
994
    {
995
      if (argv[i][0] == '-')
996
        {
997
          if (argv[i][1] == '\0')
998
            {
999
              /* Read stdin.  */
1000
              if (already_read_stdin)
1001
                fatal ("cannot read standard input twice");
1002
 
1003
              base_dir = NULL;
1004
              read_rtx_filename = in_fname = "<stdin>";
1005
              read_rtx_lineno = 1;
1006
              input_file = stdin;
1007
              already_read_stdin = true;
1008
 
1009
              while (read_rtx (input_file, &desc, &lineno))
1010
                process_rtx (desc, lineno);
1011
              fclose (input_file);
1012
              continue;
1013
            }
1014
          else if (argv[i][1] == '-' && argv[i][2] == '\0')
1015
            {
1016
              /* No further arguments are to be treated as options.  */
1017
              no_more_options = true;
1018
              continue;
1019
            }
1020
          else if (!no_more_options)
1021
            continue;
1022
        }
1023
 
1024
      /* If we get here we are looking at a non-option argument, i.e.
1025
         a file to be processed.  */
1026
 
1027
      in_fname = argv[i];
1028
      lastsl = strrchr (in_fname, '/');
1029
      if (lastsl != NULL)
1030
        base_dir = save_string (in_fname, lastsl - in_fname + 1 );
1031
      else
1032
        base_dir = NULL;
1033
 
1034
      read_rtx_filename = in_fname;
1035
      read_rtx_lineno = 1;
1036
      input_file = fopen (in_fname, "r");
1037
      if (input_file == 0)
1038
        {
1039
          perror (in_fname);
1040
          return FATAL_EXIT_CODE;
1041
        }
1042
 
1043
      while (read_rtx (input_file, &desc, &lineno))
1044
        process_rtx (desc, lineno);
1045
      fclose (input_file);
1046
    }
1047
 
1048
  /* If we get to this point without having seen any files to process,
1049
     read standard input now.  */
1050
  if (!in_fname)
1051
    {
1052
      base_dir = NULL;
1053
      read_rtx_filename = in_fname = "<stdin>";
1054
      read_rtx_lineno = 1;
1055
      input_file = stdin;
1056
 
1057
      while (read_rtx (input_file, &desc, &lineno))
1058
        process_rtx (desc, lineno);
1059
      fclose (input_file);
1060
    }
1061
 
1062
  /* Process define_cond_exec patterns.  */
1063
  if (define_cond_exec_queue != NULL)
1064
    process_define_cond_exec ();
1065
 
1066
  return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
1067
}
1068
 
1069
/* Programs that don't have their own options can use this entry point
1070
   instead.  */
1071
int
1072
init_md_reader_args (int argc, char **argv)
1073
{
1074
  return init_md_reader_args_cb (argc, argv, 0);
1075
}
1076
 
1077
/* The entry point for reading a single rtx from an md file.  */
1078
 
1079
rtx
1080
read_md_rtx (int *lineno, int *seqnr)
1081
{
1082
  struct queue_elem **queue, *elem;
1083
  rtx desc;
1084
 
1085
 discard:
1086
 
1087
  /* Read all patterns from a given queue before moving on to the next.  */
1088
  if (define_attr_queue != NULL)
1089
    queue = &define_attr_queue;
1090
  else if (define_pred_queue != NULL)
1091
    queue = &define_pred_queue;
1092
  else if (define_insn_queue != NULL)
1093
    queue = &define_insn_queue;
1094
  else if (other_queue != NULL)
1095
    queue = &other_queue;
1096
  else
1097
    return NULL_RTX;
1098
 
1099
  elem = *queue;
1100
  *queue = elem->next;
1101
  desc = elem->data;
1102
  read_rtx_filename = elem->filename;
1103
  *lineno = elem->lineno;
1104
  *seqnr = sequence_num;
1105
 
1106
  free (elem);
1107
 
1108
  /* Discard insn patterns which we know can never match (because
1109
     their C test is provably always false).  If insn_elision is
1110
     false, our caller needs to see all the patterns.  Note that the
1111
     elided patterns are never counted by the sequence numbering; it
1112
     it is the caller's responsibility, when insn_elision is false, not
1113
     to use elided pattern numbers for anything.  */
1114
  switch (GET_CODE (desc))
1115
    {
1116
    case DEFINE_INSN:
1117
    case DEFINE_EXPAND:
1118
      if (maybe_eval_c_test (XSTR (desc, 2)) != 0)
1119
        sequence_num++;
1120
      else if (insn_elision)
1121
        goto discard;
1122
 
1123
      /* *seqnr is used here so the name table will match caller's
1124
         idea of insn numbering, whether or not elision is active.  */
1125
      record_insn_name (*seqnr, XSTR (desc, 0));
1126
      break;
1127
 
1128
    case DEFINE_SPLIT:
1129
    case DEFINE_PEEPHOLE:
1130
    case DEFINE_PEEPHOLE2:
1131
      if (maybe_eval_c_test (XSTR (desc, 1)) != 0)
1132
        sequence_num++;
1133
      else if (insn_elision)
1134
            goto discard;
1135
      break;
1136
 
1137
    default:
1138
      break;
1139
    }
1140
 
1141
  return desc;
1142
}
1143
 
1144
/* Helper functions for insn elision.  */
1145
 
1146
/* Compute a hash function of a c_test structure, which is keyed
1147
   by its ->expr field.  */
1148
hashval_t
1149
hash_c_test (const void *x)
1150
{
1151
  const struct c_test *a = (const struct c_test *) x;
1152
  const unsigned char *base, *s = (const unsigned char *) a->expr;
1153
  hashval_t hash;
1154
  unsigned char c;
1155
  unsigned int len;
1156
 
1157
  base = s;
1158
  hash = 0;
1159
 
1160
  while ((c = *s++) != '\0')
1161
    {
1162
      hash += c + (c << 17);
1163
      hash ^= hash >> 2;
1164
    }
1165
 
1166
  len = s - base;
1167
  hash += len + (len << 17);
1168
  hash ^= hash >> 2;
1169
 
1170
  return hash;
1171
}
1172
 
1173
/* Compare two c_test expression structures.  */
1174
int
1175
cmp_c_test (const void *x, const void *y)
1176
{
1177
  const struct c_test *a = (const struct c_test *) x;
1178
  const struct c_test *b = (const struct c_test *) y;
1179
 
1180
  return !strcmp (a->expr, b->expr);
1181
}
1182
 
1183
/* Given a string representing a C test expression, look it up in the
1184
   condition_table and report whether or not its value is known
1185
   at compile time.  Returns a tristate: 1 for known true, 0 for
1186
   known false, -1 for unknown.  */
1187
int
1188
maybe_eval_c_test (const char *expr)
1189
{
1190
  const struct c_test *test;
1191
  struct c_test dummy;
1192
 
1193
  if (expr[0] == 0)
1194
    return 1;
1195
 
1196
  dummy.expr = expr;
1197
  test = (const struct c_test *)htab_find (condition_table, &dummy);
1198
  if (!test)
1199
    return -1;
1200
  return test->value;
1201
}
1202
 
1203
/* Record the C test expression EXPR in the condition_table, with
1204
   value VAL.  Duplicates clobber previous entries.  */
1205
 
1206
void
1207
add_c_test (const char *expr, int value)
1208
{
1209
  struct c_test *test;
1210
 
1211
  if (expr[0] == 0)
1212
    return;
1213
 
1214
  test = XNEW (struct c_test);
1215
  test->expr = expr;
1216
  test->value = value;
1217
 
1218
  *(htab_find_slot (condition_table, test, INSERT)) = test;
1219
}
1220
 
1221
/* For every C test, call CALLBACK with two arguments: a pointer to
1222
   the condition structure and INFO.  Stops when CALLBACK returns zero.  */
1223
void
1224
traverse_c_tests (htab_trav callback, void *info)
1225
{
1226
  if (condition_table)
1227
    htab_traverse (condition_table, callback, info);
1228
}
1229
 
1230
 
1231
/* Given a string, return the number of comma-separated elements in it.
1232
   Return 0 for the null string.  */
1233
int
1234
n_comma_elts (const char *s)
1235
{
1236
  int n;
1237
 
1238
  if (*s == '\0')
1239
    return 0;
1240
 
1241
  for (n = 1; *s; s++)
1242
    if (*s == ',')
1243
      n++;
1244
 
1245
  return n;
1246
}
1247
 
1248
/* Given a pointer to a (char *), return a pointer to the beginning of the
1249
   next comma-separated element in the string.  Advance the pointer given
1250
   to the end of that element.  Return NULL if at end of string.  Caller
1251
   is responsible for copying the string if necessary.  White space between
1252
   a comma and an element is ignored.  */
1253
 
1254
const char *
1255
scan_comma_elt (const char **pstr)
1256
{
1257
  const char *start;
1258
  const char *p = *pstr;
1259
 
1260
  if (*p == ',')
1261
    p++;
1262
  while (ISSPACE(*p))
1263
    p++;
1264
 
1265
  if (*p == '\0')
1266
    return NULL;
1267
 
1268
  start = p;
1269
 
1270
  while (*p != ',' && *p != '\0')
1271
    p++;
1272
 
1273
  *pstr = p;
1274
  return start;
1275
}
1276
 
1277
/* Helper functions for define_predicate and define_special_predicate
1278
   processing.  Shared between genrecog.c and genpreds.c.  */
1279
 
1280
static htab_t predicate_table;
1281
struct pred_data *first_predicate;
1282
static struct pred_data **last_predicate = &first_predicate;
1283
 
1284
static hashval_t
1285
hash_struct_pred_data (const void *ptr)
1286
{
1287
  return htab_hash_string (((const struct pred_data *)ptr)->name);
1288
}
1289
 
1290
static int
1291
eq_struct_pred_data (const void *a, const void *b)
1292
{
1293
  return !strcmp (((const struct pred_data *)a)->name,
1294
                  ((const struct pred_data *)b)->name);
1295
}
1296
 
1297
struct pred_data *
1298
lookup_predicate (const char *name)
1299
{
1300
  struct pred_data key;
1301
  key.name = name;
1302
  return (struct pred_data *) htab_find (predicate_table, &key);
1303
}
1304
 
1305
/* Record that predicate PRED can accept CODE.  */
1306
 
1307
void
1308
add_predicate_code (struct pred_data *pred, enum rtx_code code)
1309
{
1310
  if (!pred->codes[code])
1311
    {
1312
      pred->num_codes++;
1313
      pred->codes[code] = true;
1314
 
1315
      if (GET_RTX_CLASS (code) != RTX_CONST_OBJ)
1316
        pred->allows_non_const = true;
1317
 
1318
      if (code != REG
1319
          && code != SUBREG
1320
          && code != MEM
1321
          && code != CONCAT
1322
          && code != PARALLEL
1323
          && code != STRICT_LOW_PART)
1324
        pred->allows_non_lvalue = true;
1325
 
1326
      if (pred->num_codes == 1)
1327
        pred->singleton = code;
1328
      else if (pred->num_codes == 2)
1329
        pred->singleton = UNKNOWN;
1330
    }
1331
}
1332
 
1333
void
1334
add_predicate (struct pred_data *pred)
1335
{
1336
  void **slot = htab_find_slot (predicate_table, pred, INSERT);
1337
  if (*slot)
1338
    {
1339
      error ("duplicate predicate definition for '%s'", pred->name);
1340
      return;
1341
    }
1342
  *slot = pred;
1343
  *last_predicate = pred;
1344
  last_predicate = &pred->next;
1345
}
1346
 
1347
/* This array gives the initial content of the predicate table.  It
1348
   has entries for all predicates defined in recog.c.  */
1349
 
1350
struct std_pred_table
1351
{
1352
  const char *name;
1353
  bool special;
1354
  bool allows_const_p;
1355
  RTX_CODE codes[NUM_RTX_CODE];
1356
};
1357
 
1358
static const struct std_pred_table std_preds[] = {
1359
  {"general_operand", false, true, {SUBREG, REG, MEM}},
1360
  {"address_operand", true, true, {SUBREG, REG, MEM, PLUS, MINUS, MULT}},
1361
  {"register_operand", false, false, {SUBREG, REG}},
1362
  {"pmode_register_operand", true, false, {SUBREG, REG}},
1363
  {"scratch_operand", false, false, {SCRATCH, REG}},
1364
  {"immediate_operand", false, true, {UNKNOWN}},
1365
  {"const_int_operand", false, false, {CONST_INT}},
1366
  {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
1367
  {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
1368
  {"nonmemory_operand", false, true, {SUBREG, REG}},
1369
  {"push_operand", false, false, {MEM}},
1370
  {"pop_operand", false, false, {MEM}},
1371
  {"memory_operand", false, false, {SUBREG, MEM}},
1372
  {"indirect_operand", false, false, {SUBREG, MEM}},
1373
  {"ordered_comparison_operator", false, false, {EQ, NE,
1374
                                                 LE, LT, GE, GT,
1375
                                                 LEU, LTU, GEU, GTU}},
1376
  {"comparison_operator", false, false, {EQ, NE,
1377
                                         LE, LT, GE, GT,
1378
                                         LEU, LTU, GEU, GTU,
1379
                                         UNORDERED, ORDERED,
1380
                                         UNEQ, UNGE, UNGT,
1381
                                         UNLE, UNLT, LTGT}}
1382
};
1383
#define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds)
1384
 
1385
/* Initialize the table of predicate definitions, starting with
1386
   the information we have on generic predicates.  */
1387
 
1388
static void
1389
init_predicate_table (void)
1390
{
1391
  size_t i, j;
1392
  struct pred_data *pred;
1393
 
1394
  predicate_table = htab_create_alloc (37, hash_struct_pred_data,
1395
                                       eq_struct_pred_data, 0,
1396
                                       xcalloc, free);
1397
 
1398
  for (i = 0; i < NUM_KNOWN_STD_PREDS; i++)
1399
    {
1400
      pred = XCNEW (struct pred_data);
1401
      pred->name = std_preds[i].name;
1402
      pred->special = std_preds[i].special;
1403
 
1404
      for (j = 0; std_preds[i].codes[j] != 0; j++)
1405
        add_predicate_code (pred, std_preds[i].codes[j]);
1406
 
1407
      if (std_preds[i].allows_const_p)
1408
        for (j = 0; j < NUM_RTX_CODE; j++)
1409
          if (GET_RTX_CLASS (j) == RTX_CONST_OBJ)
1410
            add_predicate_code (pred, (enum rtx_code) j);
1411
 
1412
      add_predicate (pred);
1413
    }
1414
}
1415
 
1416
/* These functions allow linkage with print-rtl.c.  Also, some generators
1417
   like to annotate their output with insn names.  */
1418
 
1419
/* Holds an array of names indexed by insn_code_number.  */
1420
static char **insn_name_ptr = 0;
1421
static int insn_name_ptr_size = 0;
1422
 
1423
const char *
1424
get_insn_name (int code)
1425
{
1426
  if (code < insn_name_ptr_size)
1427
    return insn_name_ptr[code];
1428
  else
1429
    return NULL;
1430
}
1431
 
1432
static void
1433
record_insn_name (int code, const char *name)
1434
{
1435
  static const char *last_real_name = "insn";
1436
  static int last_real_code = 0;
1437
  char *new_name;
1438
 
1439
  if (insn_name_ptr_size <= code)
1440
    {
1441
      int new_size;
1442
      new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
1443
      insn_name_ptr = XRESIZEVEC (char *, insn_name_ptr, new_size);
1444
      memset (insn_name_ptr + insn_name_ptr_size, 0,
1445
              sizeof(char *) * (new_size - insn_name_ptr_size));
1446
      insn_name_ptr_size = new_size;
1447
    }
1448
 
1449
  if (!name || name[0] == '\0')
1450
    {
1451
      new_name = XNEWVAR (char, strlen (last_real_name) + 10);
1452
      sprintf (new_name, "%s+%d", last_real_name, code - last_real_code);
1453
    }
1454
  else
1455
    {
1456
      last_real_name = new_name = xstrdup (name);
1457
      last_real_code = code;
1458
    }
1459
 
1460
  insn_name_ptr[code] = new_name;
1461
}

powered by: WebSVN 2.1.0

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