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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [common/] [hw-tree.c] - Blame information for rev 578

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

Line No. Rev Author Line
1 578 markom
/*  This file is part of the program psim.
2
 
3
    Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
4
 
5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation; either version 2 of the License, or
8
    (at your option) any later version.
9
 
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
 
15
    You should have received a copy of the GNU General Public License
16
    along with this program; if not, write to the Free Software
17
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 
19
    */
20
 
21
#include "hw-main.h"
22
#include "hw-base.h"
23
#include "hw-tree.h"
24
 
25
#include "sim-io.h"
26
#include "sim-assert.h"
27
 
28
#ifdef HAVE_STDLIB_H
29
#include <stdlib.h>
30
#endif
31
 
32
#ifdef HAVE_STRING_H
33
#include <string.h>
34
#else
35
#ifdef HAVE_STRINGS_H
36
#include <strings.h>
37
#endif
38
#endif
39
 
40
#include <ctype.h>
41
 
42
/* manipulate/lookup device names */
43
 
44
typedef struct _name_specifier {
45
 
46
  /* components in the full length name */
47
  char *path;
48
  char *property;
49
  char *value;
50
 
51
  /* current device */
52
  char *family;
53
  char *name;
54
  char *unit;
55
  char *args;
56
 
57
  /* previous device */
58
  char *last_name;
59
  char *last_family;
60
  char *last_unit;
61
  char *last_args;
62
 
63
  /* work area */
64
  char buf[1024];
65
 
66
} name_specifier;
67
 
68
 
69
 
70
/* Given a device specifier, break it up into its main components:
71
   path (and if present) property name and property value. */
72
 
73
static int
74
split_device_specifier (struct hw *current,
75
                        const char *device_specifier,
76
                        name_specifier *spec)
77
{
78
  char *chp = NULL;
79
 
80
  /* expand any leading alias if present */
81
  if (current != NULL
82
      && *device_specifier != '\0'
83
      && *device_specifier != '.'
84
      && *device_specifier != '/')
85
    {
86
      struct hw *aliases = hw_tree_find_device (current, "/aliases");
87
      char alias[32];
88
      int len = 0;
89
      while (device_specifier[len] != '\0'
90
             && device_specifier[len] != '/'
91
             && device_specifier[len] != ':'
92
             && !isspace (device_specifier[len]))
93
        {
94
          alias[len] = device_specifier[len];
95
          len++;
96
          if (len >= sizeof(alias))
97
            hw_abort (NULL, "split_device_specifier: buffer overflow");
98
        }
99
      alias[len] = '\0';
100
      if (aliases != NULL
101
          && hw_find_property (aliases, alias))
102
        {
103
          strcpy (spec->buf, hw_find_string_property(aliases, alias));
104
          strcat (spec->buf, device_specifier + len);
105
        }
106
      else
107
        {
108
          strcpy (spec->buf, device_specifier);
109
        }
110
    }
111
  else
112
    {
113
      strcpy(spec->buf, device_specifier);
114
    }
115
 
116
  /* check no overflow */
117
  if (strlen(spec->buf) >= sizeof(spec->buf))
118
    hw_abort (NULL, "split_device_specifier: buffer overflow\n");
119
 
120
  /* strip leading spaces */
121
  chp = spec->buf;
122
  while (*chp != '\0' && isspace(*chp))
123
    chp++;
124
  if (*chp == '\0')
125
    return 0;
126
 
127
  /* find the path and terminate it with null */
128
  spec->path = chp;
129
  while (*chp != '\0' && !isspace(*chp))
130
    chp++;
131
  if (*chp != '\0')
132
    {
133
      *chp = '\0';
134
      chp++;
135
    }
136
 
137
  /* and any value */
138
  while (*chp != '\0' && isspace(*chp))
139
    chp++;
140
  spec->value = chp;
141
 
142
  /* now go back and chop the property off of the path */
143
  if (spec->value[0] == '\0')
144
    {
145
      spec->property = NULL; /*not a property*/
146
      spec->value = NULL;
147
    }
148
  else if (spec->value[0] == '>'
149
           || spec->value[0] == '<')
150
    {
151
      /* an interrupt spec */
152
      spec->property = NULL;
153
    }
154
  else {
155
    chp = strrchr(spec->path, '/');
156
    if (chp == NULL)
157
      {
158
        spec->property = spec->path;
159
        spec->path = strchr(spec->property, '\0');
160
      }
161
    else {
162
      *chp = '\0';
163
      spec->property = chp+1;
164
    }
165
  }
166
 
167
  /* and mark the rest as invalid */
168
  spec->name = NULL;
169
  spec->family = NULL;
170
  spec->unit = NULL;
171
  spec->args = NULL;
172
  spec->last_name = NULL;
173
  spec->last_family = NULL;
174
  spec->last_unit = NULL;
175
  spec->last_args = NULL;
176
 
177
  return 1;
178
}
179
 
180
 
181
/* given a device specifier break it up into its main components -
182
   path and property name - assuming that the last `device' is a
183
   property name. */
184
 
185
static int
186
split_property_specifier (struct hw *current,
187
                          const char *property_specifier,
188
                          name_specifier *spec)
189
{
190
  if (split_device_specifier (current, property_specifier, spec))
191
    {
192
      if (spec->property == NULL)
193
        {
194
          /* force the last name to be a property name */
195
          char *chp = strrchr (spec->path, '/');
196
          if (chp == NULL)
197
            {
198
              spec->property = spec->path;
199
              spec->path = strrchr (spec->property, '\0');;
200
            }
201
          else
202
            {
203
              *chp = '\0';
204
              spec->property = chp + 1;
205
            }
206
        }
207
      return 1;
208
    }
209
  else
210
    return 0;
211
}
212
 
213
 
214
/* device the next device name and split it up, return 0 when no more
215
   names to struct hw */
216
 
217
static int
218
split_device_name (name_specifier *spec)
219
{
220
  char *chp;
221
  /* remember what came before */
222
  spec->last_name = spec->name;
223
  spec->last_family = spec->family;
224
  spec->last_unit = spec->unit;
225
  spec->last_args = spec->args;
226
  /* finished? */
227
  if (spec->path[0] == '\0')
228
    {
229
      spec->name = NULL;
230
      spec->family = NULL;
231
      spec->unit = NULL;
232
      spec->args = NULL;
233
      return 0;
234
    }
235
  /* break the current device spec from the path */
236
  spec->name = spec->path;
237
  chp = strchr (spec->name, '/');
238
  if (chp == NULL)
239
    spec->path = strchr (spec->name, '\0');
240
  else
241
    {
242
      spec->path = chp+1;
243
      *chp = '\0';
244
    }
245
  /* break out the base */
246
  if (spec->name[0] == '(')
247
    {
248
      chp = strchr(spec->name, ')');
249
      if (chp == NULL)
250
        {
251
          spec->family = spec->name;
252
        }
253
      else
254
        {
255
          *chp = '\0';
256
          spec->family = spec->name + 1;
257
          spec->name = chp + 1;
258
        }
259
    }
260
  else
261
    {
262
      spec->family = spec->name;
263
    }
264
  /* now break out the unit */
265
  chp = strchr(spec->name, '@');
266
  if (chp == NULL)
267
    {
268
      spec->unit = NULL;
269
      chp = spec->name;
270
    }
271
  else
272
    {
273
      *chp = '\0';
274
      chp += 1;
275
      spec->unit = chp;
276
    }
277
  /* finally any args */
278
  chp = strchr(chp, ':');
279
  if (chp == NULL)
280
    spec->args = NULL;
281
  else
282
    {
283
      *chp = '\0';
284
      spec->args = chp+1;
285
    }
286
  return 1;
287
}
288
 
289
 
290
/* device the value, returning the next non-space token */
291
 
292
static char *
293
split_value (name_specifier *spec)
294
{
295
  char *token;
296
  if (spec->value == NULL)
297
    return NULL;
298
  /* skip leading white space */
299
  while (isspace (spec->value[0]))
300
    spec->value++;
301
  if (spec->value[0] == '\0')
302
    {
303
      spec->value = NULL;
304
      return NULL;
305
    }
306
  token = spec->value;
307
  /* find trailing space */
308
  while (spec->value[0] != '\0' && !isspace (spec->value[0]))
309
    spec->value++;
310
  /* chop this value out */
311
  if (spec->value[0] != '\0')
312
    {
313
      spec->value[0] = '\0';
314
      spec->value++;
315
    }
316
  return token;
317
}
318
 
319
 
320
 
321
/* traverse the path specified by spec starting at current */
322
 
323
static struct hw *
324
split_find_device (struct hw *current,
325
                   name_specifier *spec)
326
{
327
  /* strip off (and process) any leading ., .., ./ and / */
328
  while (1)
329
    {
330
      if (strncmp (spec->path, "/", strlen ("/")) == 0)
331
        {
332
          /* cd /... */
333
          while (current != NULL && hw_parent (current) != NULL)
334
            current = hw_parent (current);
335
          spec->path += strlen ("/");
336
        }
337
      else if (strncmp (spec->path, "./", strlen ("./")) == 0)
338
        {
339
          /* cd ./... */
340
          current = current;
341
          spec->path += strlen ("./");
342
        }
343
      else if (strncmp (spec->path, "../", strlen ("../")) == 0)
344
        {
345
          /* cd ../... */
346
          if (current != NULL && hw_parent (current) != NULL)
347
            current = hw_parent (current);
348
          spec->path += strlen ("../");
349
        }
350
      else if (strcmp (spec->path, ".") == 0)
351
        {
352
          /* cd . */
353
          current = current;
354
          spec->path += strlen (".");
355
        }
356
      else if (strcmp (spec->path, "..") == 0)
357
        {
358
          /* cd .. */
359
          if (current != NULL && hw_parent (current) != NULL)
360
            current = hw_parent (current);
361
          spec->path += strlen ("..");
362
        }
363
      else
364
        break;
365
    }
366
 
367
  /* now go through the path proper */
368
 
369
  if (current == NULL)
370
    {
371
      split_device_name (spec);
372
      return NULL;
373
    }
374
 
375
  while (split_device_name (spec))
376
    {
377
      struct hw *child;
378
      for (child = hw_child (current);
379
           child != NULL; child = hw_sibling (child))
380
        {
381
          if (strcmp (spec->name, hw_name (child)) == 0)
382
            {
383
              if (spec->unit == NULL)
384
                break;
385
              else
386
                {
387
                  hw_unit phys;
388
                  hw_unit_decode (current, spec->unit, &phys);
389
                  if (memcmp (&phys, hw_unit_address (child),
390
                              sizeof (hw_unit)) == 0)
391
                    break;
392
                }
393
            }
394
        }
395
      if (child == NULL)
396
        return current; /* search failed */
397
      current = child;
398
    }
399
 
400
  return current;
401
}
402
 
403
 
404
static struct hw *
405
split_fill_path (struct hw *current,
406
                 const char *device_specifier,
407
                 name_specifier *spec)
408
{
409
  /* break it up */
410
  if (!split_device_specifier (current, device_specifier, spec))
411
    hw_abort (current, "error parsing %s\n", device_specifier);
412
 
413
  /* fill our tree with its contents */
414
  current = split_find_device (current, spec);
415
 
416
  /* add any additional devices as needed */
417
  if (spec->name != NULL)
418
    {
419
      do
420
        {
421
          if (current != NULL && !hw_finished_p (current))
422
            hw_finish (current);
423
          current = hw_create (NULL,
424
                               current,
425
                               spec->family,
426
                               spec->name,
427
                               spec->unit,
428
                               spec->args);
429
        }
430
      while (split_device_name (spec));
431
    }
432
 
433
  return current;
434
}
435
 
436
 
437
/* <non-white-space> */
438
 
439
static const char *
440
skip_token(const char *chp)
441
{
442
  while (!isspace(*chp) && *chp != '\0')
443
    chp++;
444
  while (isspace(*chp) && *chp != '\0')
445
    chp++;
446
  return chp;
447
}
448
 
449
 
450
/* count the number of entries */
451
 
452
static int
453
count_entries (struct hw *current,
454
               const char *property_name,
455
               const char *property_value,
456
               int modulo)
457
{
458
  const char *chp = property_value;
459
  int nr_entries = 0;
460
  while (*chp != '\0')
461
    {
462
      nr_entries += 1;
463
      chp = skip_token (chp);
464
    }
465
  if ((nr_entries % modulo) != 0)
466
    {
467
      hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d",
468
                property_name, property_value, modulo);
469
    }
470
  return nr_entries / modulo;
471
}
472
 
473
 
474
 
475
/* parse: <address> ::= <token> ; device dependant */
476
 
477
static const char *
478
parse_address (struct hw *current,
479
               struct hw *bus,
480
               const char *chp,
481
               hw_unit *address)
482
{
483
  if (hw_unit_decode (bus, chp, address) < 0)
484
    hw_abort (current, "invalid unit address in %s", chp);
485
  return skip_token (chp);
486
}
487
 
488
 
489
/* parse: <size> ::= <number> { "," <number> } ; */
490
 
491
static const char *
492
parse_size (struct hw *current,
493
            struct hw *bus,
494
            const char *chp,
495
            hw_unit *size)
496
{
497
  int i;
498
  int nr;
499
  const char *curr = chp;
500
  memset(size, 0, sizeof(*size));
501
  /* parse the numeric list */
502
  size->nr_cells = hw_unit_nr_size_cells (bus);
503
  nr = 0;
504
  while (1)
505
    {
506
      char *next;
507
      size->cells[nr] = strtoul (curr, &next, 0);
508
      if (curr == next)
509
        hw_abort (current, "Problem parsing <size> %s", chp);
510
      nr += 1;
511
      if (next[0] != ',')
512
        break;
513
      if (nr == size->nr_cells)
514
        hw_abort (current, "Too many values in <size> %s", chp);
515
      curr = next + 1;
516
    }
517
  ASSERT (nr > 0 && nr <= size->nr_cells);
518
  /* right align the numbers */
519
  for (i = 1; i <= size->nr_cells; i++)
520
    {
521
      if (i <= nr)
522
        size->cells[size->nr_cells - i] = size->cells[nr - i];
523
      else
524
        size->cells[size->nr_cells - i] = 0;
525
    }
526
  return skip_token (chp);
527
}
528
 
529
 
530
/* parse: <reg> ::= { <address> <size> } ; */
531
 
532
static void
533
parse_reg_property (struct hw *current,
534
                    const char *property_name,
535
                    const char *property_value)
536
{
537
  int nr_regs;
538
  int reg_nr;
539
  reg_property_spec *regs;
540
  const char *chp;
541
 
542
  /* determine the number of reg entries by counting tokens */
543
  nr_regs = count_entries (current, property_name, property_value, 2);
544
 
545
  /* create working space */
546
  regs = zalloc (nr_regs * sizeof (*regs));
547
 
548
  /* fill it in */
549
  chp = property_value;
550
  for (reg_nr = 0; reg_nr < nr_regs; reg_nr++)
551
    {
552
      chp = parse_address (current, hw_parent(current),
553
                           chp, &regs[reg_nr].address);
554
      chp = parse_size (current, hw_parent(current),
555
                        chp, &regs[reg_nr].size);
556
    }
557
 
558
  /* create it */
559
  hw_add_reg_array_property (current, property_name,
560
                             regs, nr_regs);
561
 
562
  zfree (regs);
563
}
564
 
565
 
566
/* { <child-address> <parent-address> <child-size> }* */
567
 
568
static void
569
parse_ranges_property (struct hw *current,
570
                       const char *property_name,
571
                       const char *property_value)
572
{
573
  int nr_ranges;
574
  int range_nr;
575
  range_property_spec *ranges;
576
  const char *chp;
577
 
578
  /* determine the number of ranges specified */
579
  nr_ranges = count_entries (current, property_name, property_value, 3);
580
 
581
  /* create a property of that size */
582
  ranges = zalloc (nr_ranges * sizeof(*ranges));
583
 
584
  /* fill it in */
585
  chp = property_value;
586
  for (range_nr = 0; range_nr < nr_ranges; range_nr++)
587
    {
588
      chp = parse_address (current, current,
589
                           chp, &ranges[range_nr].child_address);
590
      chp = parse_address (current, hw_parent(current),
591
                           chp, &ranges[range_nr].parent_address);
592
      chp = parse_size (current, current,
593
                        chp, &ranges[range_nr].size);
594
    }
595
 
596
  /* create it */
597
  hw_add_range_array_property (current, property_name, ranges, nr_ranges);
598
 
599
  zfree (ranges);
600
}
601
 
602
 
603
/* <integer> ... */
604
 
605
static void
606
parse_integer_property (struct hw *current,
607
                        const char *property_name,
608
                        const char *property_value)
609
{
610
  int nr_entries;
611
  unsigned_cell words[1024];
612
  /* integer or integer array? */
613
  nr_entries = 0;
614
  while (1)
615
    {
616
      char *end;
617
      words[nr_entries] = strtoul (property_value, &end, 0);
618
      if (property_value == end)
619
        break;
620
      nr_entries += 1;
621
      if (nr_entries * sizeof (words[0]) >= sizeof (words))
622
        hw_abort (current, "buffer overflow");
623
      property_value = end;
624
    }
625
  if (nr_entries == 0)
626
    hw_abort (current, "error parsing integer property %s (%s)",
627
              property_name, property_value);
628
  else if (nr_entries == 1)
629
    hw_add_integer_property (current, property_name, words[0]);
630
  else
631
    {
632
      int i;
633
      for (i = 0; i < nr_entries; i++)
634
        {
635
          H2BE (words[i]);
636
        }
637
      /* perhaphs integer array property is better */
638
      hw_add_array_property (current, property_name, words,
639
                             sizeof(words[0]) * nr_entries);
640
    }
641
}
642
 
643
 
644
/* <string> ... */
645
 
646
static void
647
parse_string_property (struct hw *current,
648
                       const char *property_name,
649
                       const char *property_value)
650
{
651
  char **strings;
652
  const char *chp;
653
  int nr_strings;
654
  int approx_nr_strings;
655
 
656
  /* get an estimate as to the number of strings by counting double
657
     quotes */
658
  approx_nr_strings = 2;
659
  for (chp = property_value; *chp; chp++)
660
    {
661
      if (*chp == '"')
662
        approx_nr_strings++;
663
    }
664
  approx_nr_strings = (approx_nr_strings) / 2;
665
 
666
  /* create a string buffer for that many (plus a null) */
667
  strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof(char*));
668
 
669
  /* now find all the strings */
670
  chp = property_value;
671
  nr_strings = 0;
672
  while (1)
673
    {
674
 
675
      /* skip leading space */
676
      while (*chp != '\0' && isspace (*chp))
677
        chp += 1;
678
      if (*chp == '\0')
679
        break;
680
 
681
      /* copy it in */
682
      if (*chp == '"')
683
        {
684
          /* a quoted string - watch for '\' et.al. */
685
          /* estimate the size and allocate space for it */
686
          int pos;
687
          chp++;
688
          pos = 0;
689
          while (chp[pos] != '\0' && chp[pos] != '"')
690
            {
691
              if (chp[pos] == '\\' && chp[pos+1] != '\0')
692
                pos += 2;
693
              else
694
                pos += 1;
695
            }
696
          strings[nr_strings] = zalloc (pos + 1);
697
          /* copy the string over */
698
          pos = 0;
699
          while (*chp != '\0' && *chp != '"')
700
            {
701
              if (*chp == '\\' && *(chp+1) != '\0') {
702
                strings[nr_strings][pos] = *(chp+1);
703
                chp += 2;
704
                pos++;
705
              }
706
              else
707
                {
708
                  strings[nr_strings][pos] = *chp;
709
                  chp += 1;
710
                  pos++;
711
                }
712
            }
713
          if (*chp != '\0')
714
            chp++;
715
          strings[nr_strings][pos] = '\0';
716
        }
717
      else
718
        {
719
          /* copy over a single unquoted token */
720
          int len = 0;
721
          while (chp[len] != '\0' && !isspace(chp[len]))
722
            len++;
723
          strings[nr_strings] = zalloc(len + 1);
724
          strncpy(strings[nr_strings], chp, len);
725
          strings[nr_strings][len] = '\0';
726
          chp += len;
727
        }
728
      nr_strings++;
729
      if (nr_strings > approx_nr_strings)
730
        hw_abort (current, "String property %s badly formatted",
731
                  property_name);
732
    }
733
  ASSERT (strings[nr_strings] == NULL); /* from zalloc */
734
 
735
  /* install it */
736
  if (nr_strings == 0)
737
    hw_add_string_property (current, property_name, "");
738
  else if (nr_strings == 1)
739
    hw_add_string_property (current, property_name, strings[0]);
740
  else
741
    {
742
      const char **specs = (const char**) strings; /* stop a bogus error */
743
      hw_add_string_array_property (current, property_name,
744
                                    specs, nr_strings);
745
    }
746
 
747
  /* flush the created string */
748
  while (nr_strings > 0)
749
    {
750
      nr_strings--;
751
      zfree (strings[nr_strings]);
752
    }
753
  zfree(strings);
754
}
755
 
756
 
757
/* <path-to-ihandle-device> */
758
 
759
#if NOT_YET
760
static void
761
parse_ihandle_property (struct hw *current,
762
                        const char *property,
763
                        const char *value)
764
{
765
  ihandle_runtime_property_spec ihandle;
766
 
767
  /* pass the full path */
768
  ihandle.full_path = value;
769
 
770
  /* save this ready for the ihandle create */
771
  hw_add_ihandle_runtime_property (current, property,
772
                                   &ihandle);
773
}
774
#endif
775
 
776
 
777
struct hw *
778
hw_tree_create (SIM_DESC sd,
779
                const char *family)
780
{
781
  return hw_create (sd, NULL, family, family, NULL, NULL);
782
}
783
 
784
void
785
hw_tree_delete (struct hw *me)
786
{
787
  /* Need to allow devices to disapear under our feet */
788
  while (hw_child (me) != NULL)
789
    {
790
      hw_tree_delete (hw_child (me));
791
    }
792
  hw_delete (me);
793
}
794
 
795
 
796
struct hw *
797
hw_tree_parse (struct hw *current,
798
               const char *fmt,
799
               ...)
800
{
801
    va_list ap;
802
    va_start (ap, fmt);
803
    current = hw_tree_vparse (current, fmt, ap);
804
    va_end (ap);
805
    return current;
806
}
807
 
808
struct hw *
809
hw_tree_vparse (struct hw *current,
810
                const char *fmt,
811
                va_list ap)
812
{
813
  char device_specifier[1024];
814
  name_specifier spec;
815
 
816
  /* format the path */
817
  vsprintf (device_specifier, fmt, ap);
818
  if (strlen (device_specifier) >= sizeof (device_specifier))
819
    hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n");
820
 
821
  /* construct the tree down to the final struct hw */
822
  current = split_fill_path (current, device_specifier, &spec);
823
 
824
  /* is there an interrupt spec */
825
  if (spec.property == NULL
826
      && spec.value != NULL)
827
    {
828
      char *op = split_value (&spec);
829
      switch (op[0])
830
        {
831
        case '>':
832
          {
833
            char *my_port_name = split_value (&spec);
834
            int my_port;
835
            char *dest_port_name = split_value (&spec);
836
            int dest_port;
837
            name_specifier dest_spec;
838
            char *dest_hw_name = split_value (&spec);
839
            struct hw *dest;
840
            /* find my name */
841
            if (!hw_finished_p (current))
842
              hw_finish (current);
843
            my_port = hw_port_decode (current, my_port_name, output_port);
844
            /* find the dest device and port */
845
            dest = split_fill_path (current, dest_hw_name, &dest_spec);
846
            if (!hw_finished_p (dest))
847
              hw_finish (dest);
848
            dest_port = hw_port_decode (dest, dest_port_name,
849
                                        input_port);
850
            /* connect the two */
851
            hw_port_attach (current,
852
                            my_port,
853
                            dest,
854
                            dest_port,
855
                            permenant_object);
856
            break;
857
          }
858
        default:
859
          hw_abort (current, "unreconised interrupt spec %s\n", spec.value);
860
          break;
861
        }
862
    }
863
 
864
  /* is there a property */
865
  if (spec.property != NULL)
866
    {
867
      if (strcmp (spec.value, "true") == 0)
868
        hw_add_boolean_property (current, spec.property, 1);
869
      else if (strcmp (spec.value, "false") == 0)
870
        hw_add_boolean_property (current, spec.property, 0);
871
      else
872
        {
873
          const struct hw_property *property;
874
          switch (spec.value[0])
875
            {
876
#if NOT_YET
877
            case '*':
878
              {
879
                parse_ihandle_property (current, spec.property, spec.value + 1);
880
                break;
881
              }
882
#endif
883
            case '[':
884
              {
885
                unsigned8 words[1024];
886
                char *curr = spec.value + 1;
887
                int nr_words = 0;
888
                while (1)
889
                  {
890
                    char *next;
891
                    words[nr_words] = H2BE_1 (strtoul (curr, &next, 0));
892
                    if (curr == next)
893
                      break;
894
                    curr = next;
895
                    nr_words += 1;
896
                  }
897
                hw_add_array_property (current, spec.property,
898
                                       words, sizeof(words[0]) * nr_words);
899
                break;
900
              }
901
            case '"':
902
              {
903
                parse_string_property (current, spec.property, spec.value);
904
                break;
905
              }
906
            case '!':
907
              {
908
                spec.value++;
909
                property = hw_tree_find_property (current, spec.value);
910
                if (property == NULL)
911
                  hw_abort (current, "property %s not found\n", spec.value);
912
                hw_add_duplicate_property (current,
913
                                           spec.property,
914
                                           property);
915
                break;
916
              }
917
            default:
918
              {
919
                if (strcmp (spec.property, "reg") == 0
920
                    || strcmp (spec.property, "assigned-addresses") == 0
921
                    || strcmp (spec.property, "alternate-reg") == 0)
922
                  {
923
                    parse_reg_property (current, spec.property, spec.value);
924
                  }
925
                else if (strcmp (spec.property, "ranges") == 0)
926
                  {
927
                    parse_ranges_property (current, spec.property, spec.value);
928
                  }
929
                else if (isdigit(spec.value[0])
930
                         || (spec.value[0] == '-' && isdigit(spec.value[1]))
931
                         || (spec.value[0] == '+' && isdigit(spec.value[1])))
932
                  {
933
                    parse_integer_property(current, spec.property, spec.value);
934
                  }
935
                else
936
                  parse_string_property(current, spec.property, spec.value);
937
                break;
938
              }
939
            }
940
        }
941
    }
942
  return current;
943
}
944
 
945
 
946
static void
947
finish_hw_tree (struct hw *me,
948
                void *data)
949
{
950
  if (!hw_finished_p (me))
951
    hw_finish (me);
952
}
953
 
954
void
955
hw_tree_finish (struct hw *root)
956
{
957
  hw_tree_traverse (root, finish_hw_tree, NULL, NULL);
958
}
959
 
960
 
961
 
962
void
963
hw_tree_traverse (struct hw *root,
964
                  hw_tree_traverse_function *prefix,
965
                  hw_tree_traverse_function *postfix,
966
                  void *data)
967
{
968
  struct hw *child;
969
  if (prefix != NULL)
970
    prefix (root, data);
971
  for (child = hw_child (root);
972
       child != NULL;
973
       child = hw_sibling (child))
974
    {
975
      hw_tree_traverse (child, prefix, postfix, data);
976
    }
977
  if (postfix != NULL)
978
    postfix (root, data);
979
}
980
 
981
 
982
 
983
struct printer {
984
  hw_tree_print_callback *print;
985
  void *file;
986
};
987
 
988
static void
989
print_address (struct hw *bus,
990
               const hw_unit *phys,
991
               struct printer *p)
992
{
993
  char unit[32];
994
  hw_unit_encode (bus, phys, unit, sizeof(unit));
995
  p->print (p->file, " %s", unit);
996
}
997
 
998
static void
999
print_size (struct hw *bus,
1000
            const hw_unit *size,
1001
            struct printer *p)
1002
{
1003
  int i;
1004
  for (i = 0; i < size->nr_cells; i++)
1005
    if (size->cells[i] != 0)
1006
      break;
1007
  if (i < size->nr_cells) {
1008
    p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]);
1009
    i++;
1010
    for (; i < size->nr_cells; i++)
1011
      p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]);
1012
  }
1013
  else
1014
    p->print (p->file, " 0");
1015
}
1016
 
1017
static void
1018
print_reg_property (struct hw *me,
1019
                    const struct hw_property *property,
1020
                    struct printer *p)
1021
{
1022
  int reg_nr;
1023
  reg_property_spec reg;
1024
  for (reg_nr = 0;
1025
       hw_find_reg_array_property (me, property->name, reg_nr, &reg);
1026
       reg_nr++) {
1027
    print_address (hw_parent (me), &reg.address, p);
1028
    print_size (me, &reg.size, p);
1029
  }
1030
}
1031
 
1032
static void
1033
print_ranges_property (struct hw *me,
1034
                       const struct hw_property *property,
1035
                       struct printer *p)
1036
{
1037
  int range_nr;
1038
  range_property_spec range;
1039
  for (range_nr = 0;
1040
       hw_find_range_array_property (me, property->name, range_nr, &range);
1041
       range_nr++)
1042
    {
1043
      print_address (me, &range.child_address, p);
1044
      print_address (hw_parent (me), &range.parent_address, p);
1045
      print_size (me, &range.size, p);
1046
    }
1047
}
1048
 
1049
static void
1050
print_string (struct hw *me,
1051
              const char *string,
1052
              struct printer *p)
1053
{
1054
  p->print (p->file, " \"");
1055
  while (*string != '\0') {
1056
    switch (*string) {
1057
    case '"':
1058
      p->print (p->file, "\\\"");
1059
      break;
1060
    case '\\':
1061
      p->print (p->file, "\\\\");
1062
      break;
1063
    default:
1064
      p->print (p->file, "%c", *string);
1065
      break;
1066
    }
1067
    string++;
1068
  }
1069
  p->print (p->file, "\"");
1070
}
1071
 
1072
static void
1073
print_string_array_property (struct hw *me,
1074
                             const struct hw_property *property,
1075
                             struct printer *p)
1076
{
1077
  int nr;
1078
  string_property_spec string;
1079
  for (nr = 0;
1080
       hw_find_string_array_property (me, property->name, nr, &string);
1081
       nr++)
1082
    {
1083
      print_string (me, string, p);
1084
    }
1085
}
1086
 
1087
static void
1088
print_properties (struct hw *me,
1089
                  struct printer *p)
1090
{
1091
  const struct hw_property *property;
1092
  for (property = hw_find_property (me, NULL);
1093
       property != NULL;
1094
       property = hw_next_property (property))
1095
    {
1096
      if (hw_parent (me) == NULL)
1097
        p->print (p->file, "/%s", property->name);
1098
      else
1099
        p->print (p->file, "%s/%s", hw_path (me), property->name);
1100
      if (property->original != NULL)
1101
        {
1102
          p->print (p->file, " !");
1103
          p->print (p->file, "%s/%s",
1104
                     hw_path (property->original->owner),
1105
                     property->original->name);
1106
        }
1107
      else
1108
        {
1109
          switch (property->type)
1110
            {
1111
            case array_property:
1112
              {
1113
                if ((property->sizeof_array % sizeof (signed_cell)) == 0)
1114
                  {
1115
                    unsigned_cell *w = (unsigned_cell*) property->array;
1116
                    int cell_nr;
1117
                    for (cell_nr = 0;
1118
                         cell_nr < (property->sizeof_array / sizeof (unsigned_cell));
1119
                         cell_nr++)
1120
                      {
1121
                        p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr]));
1122
                      }
1123
                  }
1124
                else
1125
                  {
1126
                    unsigned8 *w = (unsigned8*)property->array;
1127
                    p->print (p->file, " [");
1128
                    while ((char*)w - (char*)property->array < property->sizeof_array) {
1129
                      p->print (p->file, " 0x%2x", BE2H_1 (*w));
1130
                      w++;
1131
                    }
1132
                  }
1133
                break;
1134
              }
1135
            case boolean_property:
1136
              {
1137
                int b = hw_find_boolean_property(me, property->name);
1138
                p->print (p->file, " %s", b ? "true"  : "false");
1139
                break;
1140
              }
1141
#if NOT_YET
1142
            case ihandle_property:
1143
              {
1144
                if (property->array != NULL)
1145
                  {
1146
                    device_instance *instance = hw_find_ihandle_property (me, property->name);
1147
                    p->print (p->file, " *%s", device_instance_path(instance));
1148
                  }
1149
                else
1150
                  {
1151
                    /* not yet initialized, ask the device for the path */
1152
                    ihandle_runtime_property_spec spec;
1153
                    hw_find_ihandle_runtime_property (me, property->name, &spec);
1154
                    p->print (p->file, " *%s", spec.full_path);
1155
                  }
1156
                break;
1157
              }
1158
#endif
1159
            case integer_property:
1160
              {
1161
                unsigned_word w = hw_find_integer_property (me, property->name);
1162
                p->print (p->file, " 0x%lx", (unsigned long)w);
1163
                break;
1164
              }
1165
            case range_array_property:
1166
              {
1167
                print_ranges_property (me, property, p);
1168
                break;
1169
              }
1170
            case reg_array_property:
1171
              {
1172
                print_reg_property (me, property, p);
1173
                break;
1174
              }
1175
            case string_property:
1176
              {
1177
                const char *s = hw_find_string_property (me, property->name);
1178
                print_string (me, s, p);
1179
                break;
1180
              }
1181
            case string_array_property:
1182
              {
1183
                print_string_array_property (me, property, p);
1184
                break;
1185
              }
1186
            }
1187
        }
1188
      p->print (p->file, "\n");
1189
    }
1190
}
1191
 
1192
static void
1193
print_interrupts (struct hw *me,
1194
                  int my_port,
1195
                  struct hw *dest,
1196
                  int dest_port,
1197
                  void *data)
1198
{
1199
  struct printer *p = data;
1200
  char src[32];
1201
  char dst[32];
1202
  hw_port_encode (me, my_port, src, sizeof(src), output_port);
1203
  hw_port_encode (dest, dest_port, dst, sizeof(dst), input_port);
1204
  p->print (p->file,
1205
            "%s > %s %s %s\n",
1206
            hw_path (me),
1207
            src, dst,
1208
            hw_path (dest));
1209
}
1210
 
1211
static void
1212
print_device (struct hw *me,
1213
              void *data)
1214
{
1215
  struct printer *p = data;
1216
  p->print (p->file, "%s\n", hw_path (me));
1217
  print_properties (me, p);
1218
  hw_port_traverse (me, print_interrupts, data);
1219
}
1220
 
1221
void
1222
hw_tree_print (struct hw *root,
1223
               hw_tree_print_callback *print,
1224
               void *file)
1225
{
1226
  struct printer p;
1227
  p.print = print;
1228
  p.file = file;
1229
  hw_tree_traverse (root,
1230
                    print_device, NULL,
1231
                    &p);
1232
}
1233
 
1234
 
1235
 
1236
#if NOT_YET
1237
device_instance *
1238
tree_instance(struct hw *root,
1239
              const char *device_specifier)
1240
{
1241
  /* find the device node */
1242
  struct hw *me;
1243
  name_specifier spec;
1244
  if (!split_device_specifier(root, device_specifier, &spec))
1245
    return NULL;
1246
  me = split_find_device(root, &spec);
1247
  if (spec.name != NULL)
1248
    return NULL;
1249
  /* create the instance */
1250
  return device_create_instance(me, device_specifier, spec.last_args);
1251
}
1252
#endif
1253
 
1254
struct hw *
1255
hw_tree_find_device (struct hw *root,
1256
                     const char *path_to_device)
1257
{
1258
  struct hw *node;
1259
  name_specifier spec;
1260
 
1261
  /* parse the path */
1262
  split_device_specifier (root, path_to_device, &spec);
1263
  if (spec.value != NULL)
1264
    return NULL; /* something wierd */
1265
 
1266
  /* now find it */
1267
  node = split_find_device (root, &spec);
1268
  if (spec.name != NULL)
1269
    return NULL; /* not a leaf */
1270
 
1271
  return node;
1272
}
1273
 
1274
 
1275
const struct hw_property *
1276
hw_tree_find_property (struct hw *root,
1277
                       const char *path_to_property)
1278
{
1279
  name_specifier spec;
1280
  if (!split_property_specifier (root, path_to_property, &spec))
1281
    hw_abort (root, "Invalid property path %s", path_to_property);
1282
  root = split_find_device (root, &spec);
1283
  if (spec.name != NULL)
1284
    return NULL; /* not a leaf */
1285
  return hw_find_property (root, spec.property);
1286
}
1287
 
1288
int
1289
hw_tree_find_boolean_property (struct hw *root,
1290
                               const char *path_to_property)
1291
{
1292
  name_specifier spec;
1293
  if (!split_property_specifier (root, path_to_property, &spec))
1294
    hw_abort (root, "Invalid property path %s", path_to_property);
1295
  root = split_find_device (root, &spec);
1296
  if (spec.name != NULL)
1297
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
1298
              spec.name, path_to_property);
1299
  return hw_find_boolean_property (root, spec.property);
1300
}
1301
 
1302
signed_cell
1303
hw_tree_find_integer_property (struct hw *root,
1304
                               const char *path_to_property)
1305
{
1306
  name_specifier spec;
1307
  if (!split_property_specifier (root, path_to_property, &spec))
1308
    hw_abort (root, "Invalid property path %s", path_to_property);
1309
  root = split_find_device (root, &spec);
1310
  if (spec.name != NULL)
1311
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
1312
              spec.name, path_to_property);
1313
  return hw_find_integer_property (root, spec.property);
1314
}
1315
 
1316
#if NOT_YET
1317
device_instance *
1318
hw_tree_find_ihandle_property (struct hw *root,
1319
                               const char *path_to_property)
1320
{
1321
  struct hw *root;
1322
  name_specifier spec;
1323
  if (!split_property_specifier (root, path_to_property, &spec))
1324
    hw_abort (root, "Invalid property path %s", path_to_property);
1325
  root = split_find_device (root, &spec);
1326
  if (spec.name != NULL)
1327
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
1328
              spec.name, path_to_property);
1329
  return hw_find_ihandle_property (root, spec.property);
1330
}
1331
#endif
1332
 
1333
const char *
1334
hw_tree_find_string_property (struct hw *root,
1335
                              const char *path_to_property)
1336
{
1337
  name_specifier spec;
1338
  if (!split_property_specifier (root, path_to_property, &spec))
1339
    hw_abort (root, "Invalid property path %s", path_to_property);
1340
  root = split_find_device (root, &spec);
1341
  if (spec.name != NULL)
1342
    hw_abort (root, "device \"%s\" not found (property \"%s\")",
1343
              spec.name, path_to_property);
1344
  return hw_find_string_property (root, spec.property);
1345
}

powered by: WebSVN 2.1.0

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