]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/device_tree.c
0d9f7687ffee2236090e30e7e2f780c3473d0ba1
[thirdparty/binutils-gdb.git] / sim / ppc / device_tree.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1995, 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
22 #ifndef _DEVICE_TREE_C_
23 #define _DEVICE_TREE_C_
24
25 #ifndef STATIC_INLINE_DEVICE_TREE
26 #define STATIC_INLINE_DEVICE_TREE STATIC_INLINE
27 #endif
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "basics.h"
34 #include "device_tree.h"
35
36 typedef enum {
37 node_any = 0,
38 node_device,
39 node_integer,
40 node_boolean,
41 node_string
42 } node_type;
43
44 static char *node_type_names[] = {
45 "any",
46 "device",
47 "integer",
48 "boolean",
49 "string",
50 NULL,
51 };
52
53 struct _device_tree {
54 /* where i am */
55 device_tree *parent;
56 device_tree *children;
57 device_tree *sibling;
58 /* what i am */
59 node_type type;
60 const char *name;
61 /* the value */
62 const device *device;
63 int boolean;
64 const char *string;
65 signed_word integer;
66 };
67
68
69 STATIC_INLINE_DEVICE_TREE device_tree *
70 new_device_tree(device_tree *parent,
71 const char *name,
72 node_type type)
73 {
74 device_tree *new_node;
75 new_node = ZALLOC(device_tree);
76 new_node->parent = parent;
77 new_node->name = strdup(name);
78 new_node->type = type;
79 if (parent != NULL) {
80 device_tree **sibling = &parent->children;
81 while ((*sibling) != NULL)
82 sibling = &(*sibling)->sibling;
83 *sibling = new_node;
84 }
85 return new_node;
86 }
87
88
89 /* find/create a node in the device tree */
90
91 typedef enum {
92 device_tree_grow = 1,
93 device_tree_return_null = 2,
94 device_tree_abort = 3,
95 } device_tree_action;
96
97 STATIC_INLINE_DEVICE_TREE device_tree *
98 device_tree_find_node(device_tree *root,
99 const char *path,
100 const char *full_path,
101 node_type type,
102 device_tree_action action)
103 {
104 const char *chp;
105 int name_len;
106 device_tree *child;
107
108 /* strip off any leading `/', `../' or `./' */
109 while (1) {
110 if (strncmp(path, "/", strlen("/")) == 0) {
111 while (root != NULL && root->parent != NULL)
112 root = root->parent;
113 path += strlen("/");
114 }
115 else if (strncmp(path, "./", strlen("./")) == 0) {
116 root = root;
117 path += strlen("./");
118 }
119 else if (strncmp(path, "../", strlen("../")) == 0) {
120 if (root != NULL && root->parent != NULL)
121 root = root->parent;
122 path += strlen("../");
123 }
124 else {
125 break;
126 }
127 }
128
129 /* find the qualified (with @) and unqualified names in the path,
130 remembering to skip any "\/" */
131 chp = path;
132 do {
133 chp = strchr(chp+1, '/');
134 } while (chp != NULL && chp[-1] == '\\');
135 name_len = (chp == NULL
136 ? strlen(path)
137 : chp - path);
138
139 /* leaf? and growing? */
140 if (root != NULL) {
141 for (child = root->children;
142 child != NULL;
143 child = child->sibling) {
144 if (strncmp(path, child->name, name_len) == 0
145 && (strlen(child->name) == name_len
146 || (strchr(child->name, '@')
147 == child->name + name_len))) {
148 if (path[name_len] == '\0') {
149 if (action == device_tree_grow)
150 error("device_tree_find_node() node %s already present\n",
151 full_path);
152 if (type != node_any && child->type != type) {
153 if (action == device_tree_return_null)
154 return NULL;
155 else
156 error("device_tree_find_node() node %s is not of type %s\n",
157 full_path, node_type_names[type]);
158 }
159 else
160 return child;
161 }
162 else
163 return device_tree_find_node(child,
164 path + name_len + 1,
165 full_path,
166 type,
167 action);
168 }
169 }
170 }
171
172 /* search failed, take default action */
173 switch (action) {
174 case device_tree_grow:
175 if (path[name_len] != '\0')
176 error("device_tree_find_node() a parent of %s missing\n",
177 full_path);
178 return new_device_tree(root, path, type);
179 case device_tree_return_null:
180 return NULL;
181 case device_tree_abort:
182 error("device_tree_find_node() could not find %s in tree\n",
183 full_path);
184 return NULL;
185 default:
186 error("device_tree_find_node() invalid default action %d\n", action);
187 return NULL;
188 }
189 }
190
191
192 /* grow the device tree */
193
194 INLINE_DEVICE_TREE device_tree *
195 device_tree_add_passthrough(device_tree *root,
196 const char *path)
197 {
198 device_tree *new_node;
199 TRACE(trace_device_tree,
200 ("device_tree_add_passthrough(root=0x%x, path=%s)\n", root, path));
201 new_node = device_tree_find_node(root,
202 path,
203 path, /*full_path*/
204 node_device,
205 device_tree_grow);
206 new_node->device = device_create_from(new_node->name,
207 path,
208 NULL,
209 passthrough_device_callbacks(),
210 new_node->parent->device);
211
212 TRACE(trace_device_tree,
213 ("device_tree_add_passthrough() = 0x%x\n", new_node));
214 return new_node;
215 }
216
217
218 INLINE_DEVICE_TREE device_tree *
219 device_tree_add_device(device_tree *root,
220 const char *path,
221 const device *dev)
222 {
223 device_tree *new_node;
224 TRACE(trace_device_tree,
225 ("device_tree_add_device(root=0x%x, path=%s, dev=0x%x)\n",
226 root, path, dev));
227 new_node = device_tree_find_node(root,
228 path,
229 path, /* full-path */
230 node_device,
231 device_tree_grow);
232 new_node->device = dev;
233 TRACE(trace_device_tree,
234 ("device_tree_add_device() = 0x%x\n", new_node));
235 return new_node;
236 }
237
238 INLINE_DEVICE_TREE device_tree *
239 device_tree_add_integer(device_tree *root,
240 const char *path,
241 signed_word integer)
242 {
243 device_tree *new_node;
244 TRACE(trace_device_tree,
245 ("device_tree_add_integer(root=0x%x, path=%s, integer=%d)\n",
246 root, path, integer));
247 new_node = device_tree_find_node(root,
248 path,
249 path, /* full-name */
250 node_integer,
251 device_tree_grow);
252 new_node->integer = integer;
253 TRACE(trace_device_tree,
254 ("device_tree_add_integer() = 0x%x\n", new_node));
255 return new_node;
256 }
257
258 INLINE_DEVICE_TREE device_tree *
259 device_tree_add_string(device_tree *root,
260 const char *path,
261 const char *string)
262 {
263 device_tree *new_node;
264 TRACE(trace_device_tree,
265 ("device_tree_add_device(root=0x%x, path=%s, string=%s)\n",
266 root, path, string));
267 new_node = device_tree_find_node(root,
268 path,
269 path, /* full-name */
270 node_string,
271 device_tree_grow);
272 new_node->string = string;
273 TRACE(trace_device_tree,
274 ("device_tree_add_string() = 0x%x\n", new_node));
275 return new_node;
276 }
277
278 INLINE_DEVICE_TREE device_tree *
279 device_tree_add_boolean(device_tree *root,
280 const char *path,
281 int boolean)
282 {
283 device_tree *new_node;
284 TRACE(trace_device_tree,
285 ("device_tree_add_boolean(root=0x%x, path=%s, boolean=%d)\n",
286 root, path, boolean));
287 new_node = device_tree_find_node(root,
288 path,
289 path, /* full-name */
290 node_boolean,
291 device_tree_grow);
292 new_node->boolean = boolean;
293 TRACE(trace_device_tree,
294 ("device_tree_add_boolean() = 0x%x\n", new_node));
295 return new_node;
296 }
297
298 INLINE_DEVICE_TREE device_tree *
299 device_tree_add_found_device(device_tree *root,
300 const char *path)
301 {
302 device_tree *new_node;
303 TRACE(trace_device_tree,
304 ("device_tree_add_found_device(root=0x%x, path=%s)\n",
305 root, path));
306 new_node = device_tree_add_device(root, path, NULL);
307 new_node->device = device_create(new_node->name,
308 path,
309 new_node->parent->device);
310 TRACE(trace_device_tree,
311 ("device_tree_add_found_device() = 0x%x\n", new_node));
312 return new_node;
313 }
314
315
316 /* look up the device tree */
317
318 INLINE_DEVICE_TREE const device *
319 device_tree_find_device(device_tree *root,
320 const char *path)
321 {
322 device_tree *node;
323 TRACE(trace_device_tree,
324 ("device_tree_find_device(root=0x%x, path=%s)\n", root, path));
325 node = device_tree_find_node(root,
326 path,
327 path, /* full-name */
328 node_device,
329 device_tree_abort);
330 TRACE(trace_device_tree,
331 ("device_tree_find_device() = 0x%x\n", node->device));
332 return node->device;
333 }
334
335 INLINE_DEVICE_TREE signed_word
336 device_tree_find_integer(device_tree *root,
337 const char *path)
338 {
339 device_tree *node;
340 TRACE(trace_device_tree,
341 ("device_tree_find_integer(root=0x%x, path=%s)\n", root, path));
342 node = device_tree_find_node(root,
343 path,
344 path, /* full-name */
345 node_integer,
346 device_tree_abort);
347 TRACE(trace_device_tree,
348 ("device_tree_find_integer() = %d\n", node->integer));
349 return node->integer;
350 }
351
352 INLINE_DEVICE_TREE const char *
353 device_tree_find_string(device_tree *root,
354 const char *path)
355 {
356 device_tree *node;
357 TRACE(trace_device_tree,
358 ("device_tree_find_string(root=0x%x, path=%s)\n", root, path));
359 node = device_tree_find_node(root,
360 path,
361 path, /* full-name */
362 node_string,
363 device_tree_abort);
364 TRACE(trace_device_tree,
365 ("device_tree_find_string() = 0x%x\n", node->string));
366 return node->string;
367 }
368
369 INLINE_DEVICE_TREE int
370 device_tree_find_boolean(device_tree *root,
371 const char *path)
372 {
373 device_tree *node;
374 TRACE(trace_device_tree,
375 ("device_tree_find_boolean(root=0x%x, path=%s)\n", root, path));
376 node = device_tree_find_node(root,
377 path,
378 path, /* full-name */
379 node_boolean,
380 device_tree_abort);
381 TRACE(trace_device_tree,
382 ("device_tree_find_boolean() = %d\n", node->boolean));
383 return node->boolean;
384 }
385
386
387 /* init all the devices */
388
389 STATIC_INLINE_DEVICE_TREE void
390 device_tree_init_device(device_tree *root,
391 void *data)
392 {
393 psim *system;
394 system = (psim*)data;
395 if (root->type == node_device) {
396 TRACE(trace_device_tree,
397 ("device_tree_init() initializing device=0x%x:%s\n",
398 root->device, root->device->full_name));
399 root->device->callback->init(root->device, system);
400 }
401 }
402
403
404 INLINE_DEVICE_TREE void
405 device_tree_init(device_tree *root,
406 psim *system)
407 {
408 TRACE(trace_device_tree,
409 ("device_tree_init(root=0x%x, system=0x%x)\n", root, system));
410 device_tree_traverse(root, device_tree_init_device, NULL, system);
411 TRACE(trace_device_tree,
412 ("device_tree_init() = void\n"));
413 }
414
415
416 /* traverse a device tree applying prefix/postfix functions to it */
417
418 INLINE_DEVICE_TREE void
419 device_tree_traverse(device_tree *root,
420 device_tree_traverse_function *prefix,
421 device_tree_traverse_function *postfix,
422 void *data)
423 {
424 device_tree *child;
425 if (prefix != NULL)
426 prefix(root, data);
427 for (child = root->children; child != NULL; child = child->sibling) {
428 device_tree_traverse(child, prefix, postfix, data);
429 }
430 if (postfix != NULL)
431 postfix(root, data);
432 }
433
434
435 /* dump out a device node and addresses */
436
437 INLINE_DEVICE_TREE void
438 device_tree_dump(device_tree *device,
439 void *ignore_data_argument)
440 {
441 printf_filtered("(device_tree@0x%x\n", device);
442 printf_filtered(" (parent 0x%x)\n", device->parent);
443 printf_filtered(" (children 0x%x)\n", device->children);
444 printf_filtered(" (sibling 0x%x)\n", device->sibling);
445 printf_filtered(" (type %d)\n", device->type);
446 printf_filtered(" (name %s)\n", device->name);
447 printf_filtered(" (device 0x%x)\n", device->device);
448 printf_filtered(" (boolean %d)\n", device->boolean);
449 printf_filtered(" (string %s)\n", device->string);
450 printf_filtered(" (integer %d)\n", device->integer);
451 printf_filtered(")\n");
452 }
453
454
455 /* Parse a device name, various formats */
456
457 #define SCAN_INIT(START, END, COUNT, NAME) \
458 char *START = NULL; \
459 char *END = strchr(NAME, '@'); \
460 int COUNT = 0; \
461 if (END == NULL) \
462 return 0; \
463 START = END + 1
464
465 #define SCAN_U(START, END, COUNT, U) \
466 do { \
467 *U = strtoul(START, &END, 0); \
468 if (START == END) \
469 return COUNT; \
470 COUNT++; \
471 if (*END != ',') \
472 return COUNT; \
473 START = END + 1; \
474 } while (0)
475
476 #define SCAN_P(START, END, COUNT, P) \
477 do { \
478 *P = (void*)(unsigned)strtouq(START, &END, 0); \
479 if (START == END) \
480 return COUNT; \
481 COUNT++; \
482 if (*END != ',') \
483 return COUNT; \
484 START = END + 1; \
485 } while (0)
486
487 #define SCAN_C(START, END, COUNT, C, SIZE) \
488 do { \
489 char *chp = C; \
490 END = START; \
491 while (*END != '\0' && *END != ',') { \
492 if (*END == '\\') \
493 END++; \
494 *chp = *END; \
495 chp += 1; \
496 END += 1; \
497 if ((SIZE) <= ((END) - (START))) \
498 return COUNT; /* overflow */ \
499 } \
500 *chp = '\0'; \
501 if (START == END) \
502 return COUNT; \
503 COUNT++; \
504 if (*END != ',') \
505 return COUNT; \
506 START = END + 1; \
507 } while (0)
508
509 INLINE_DEVICE_TREE int
510 scand_uw(const char *name,
511 unsigned_word *uw1)
512 {
513 SCAN_INIT(start, end, count, name);
514 SCAN_U(start, end, count, uw1);
515 return count;
516 }
517
518 INLINE_DEVICE_TREE int
519 scand_uw_u(const char *name,
520 unsigned_word *uw1,
521 unsigned *u2)
522 {
523 SCAN_INIT(start, end, count, name);
524 SCAN_U(start, end, count, uw1);
525 SCAN_U(start, end, count, u2);
526 return count;
527 }
528
529 INLINE_DEVICE_TREE int
530 scand_uw_u_u(const char *name,
531 unsigned_word *uw1,
532 unsigned *u2,
533 unsigned *u3)
534 {
535 SCAN_INIT(start, end, count, name);
536 SCAN_U(start, end, count, uw1);
537 SCAN_U(start, end, count, u2);
538 SCAN_U(start, end, count, u3);
539 return count;
540 }
541
542 INLINE_DEVICE_TREE int
543 scand_uw_uw_u(const char *name,
544 unsigned_word *uw1,
545 unsigned_word *uw2,
546 unsigned *u3)
547 {
548 SCAN_INIT(start, end, count, name);
549 SCAN_U(start, end, count, uw1);
550 SCAN_U(start, end, count, uw2);
551 SCAN_U(start, end, count, u3);
552 return count;
553 }
554
555 INLINE_DEVICE_TREE int
556 scand_c(const char *name,
557 char *c1, int c1size)
558 {
559 SCAN_INIT(start, end, count, name);
560 SCAN_C(start, end, count, c1, c1size);
561 return count;
562 }
563
564 INLINE_DEVICE_TREE int
565 scand_c_uw_u(const char *name,
566 char *c1, int c1size,
567 unsigned_word *uw2,
568 unsigned *u3)
569 {
570 SCAN_INIT(start, end, count, name);
571 SCAN_C(start, end, count, c1, c1size);
572 SCAN_U(start, end, count, uw2);
573 SCAN_U(start, end, count, u3);
574 return count;
575 }
576
577
578 STATIC_INLINE_DEVICE_TREE void
579 u_strcat(char *buf,
580 unsigned_word uw)
581 {
582 if (MASKED64(uw, 32, 63) == uw
583 || WITH_HOST_WORD_BITSIZE == 64) {
584 char *end = strchr(buf, '\0');
585 sprintf(end, "0x%x", (unsigned)uw);
586 }
587 else {
588 char *end = strchr(buf, '\0');
589 sprintf(end, "0x%x%08x",
590 (unsigned)EXTRACTED64(uw, 0, 31),
591 (unsigned)EXTRACTED64(uw, 32, 63));
592 }
593 }
594
595 STATIC_INLINE_DEVICE_TREE void
596 c_strcat(char *buf,
597 const char *c)
598 {
599 char *end = strchr(buf, '\0');
600 while (*c) {
601 if (*c == '/' || *c == ',')
602 *end++ = '\\';
603 *end++ = *c++;
604 }
605 *end = '\0';
606 }
607
608 STATIC_INLINE_DEVICE_TREE int
609 c_strlen(const char *c)
610 {
611 int len = 0;
612 while (*c) {
613 if (*c == '/' || *c == ',')
614 len++;
615 len++;
616 c++;
617 }
618 return len;
619 }
620
621 enum {
622 strlen_unsigned = 10,
623 strlen_unsigned_word = 18,
624 };
625
626 INLINE_DEVICE_TREE char *
627 printd_uw_u(const char *name,
628 unsigned_word uw1,
629 unsigned u2)
630 {
631 int sizeof_buf = (strlen(name)
632 + strlen("@")
633 + strlen_unsigned_word
634 + strlen(",")
635 + strlen_unsigned
636 + 1);
637 char *buf = (char*)zalloc(sizeof_buf);
638 strcpy(buf, name);
639 strcat(buf, "@");
640 u_strcat(buf, uw1);
641 strcat(buf, ",");
642 u_strcat(buf, u2);
643 ASSERT(strlen(buf) < sizeof_buf);
644 return buf;
645 }
646
647 INLINE_DEVICE_TREE char *
648 printd_uw_u_u(const char *name,
649 unsigned_word uw1,
650 unsigned u2,
651 unsigned u3)
652 {
653 int sizeof_buf = (strlen(name)
654 + strlen("@")
655 + strlen_unsigned_word
656 + strlen(",")
657 + strlen_unsigned
658 + strlen(",")
659 + strlen_unsigned
660 + 1);
661 char *buf = (char*)zalloc(sizeof_buf);
662 strcpy(buf, name);
663 strcat(buf, "@");
664 u_strcat(buf, uw1);
665 strcat(buf, ",");
666 u_strcat(buf, u2);
667 strcat(buf, ",");
668 u_strcat(buf, u3);
669 ASSERT(strlen(buf) < sizeof_buf);
670 return buf;
671 }
672
673 INLINE_DEVICE_TREE char *
674 printd_uw_u_u_c(const char *name,
675 unsigned_word uw1,
676 unsigned u2,
677 unsigned u3,
678 const char *c4)
679 {
680 int sizeof_buf = (strlen(name)
681 + strlen("@")
682 + strlen_unsigned_word
683 + strlen(",")
684 + strlen_unsigned
685 + strlen(",")
686 + strlen_unsigned
687 + strlen(",")
688 + c_strlen(c4)
689 + 1);
690 char *buf = (char*)zalloc(sizeof_buf);
691 strcpy(buf, name);
692 strcat(buf, "@");
693 u_strcat(buf, uw1);
694 strcat(buf, ",");
695 u_strcat(buf, u2);
696 strcat(buf, ",");
697 u_strcat(buf, u3);
698 strcat(buf, ",");
699 c_strcat(buf, c4);
700 ASSERT(strlen(buf) < sizeof_buf);
701 return buf;
702 }
703
704 INLINE_DEVICE_TREE char *
705 printd_c(const char *name,
706 const char *c1)
707 {
708 int sizeof_buf = (strlen(name)
709 + strlen("@")
710 + c_strlen(c1)
711 + 1);
712 char *buf = (char*)zalloc(sizeof_buf);
713 strcpy(buf, name);
714 strcat(buf, "@");
715 c_strcat(buf, c1);
716 ASSERT(strlen(buf) < sizeof_buf);
717 return buf;
718 }
719
720 INLINE_DEVICE_TREE char *
721 printd_c_uw(const char *name,
722 const char *c1,
723 unsigned_word uw2)
724 {
725 int sizeof_buf = (strlen(name)
726 + strlen("@")
727 + c_strlen(c1)
728 + strlen(",")
729 + strlen_unsigned_word
730 + 1);
731 char *buf = (char*)zalloc(sizeof_buf);
732 strcpy(buf, name);
733 strcat(buf, "@");
734 c_strcat(buf, c1);
735 strcat(buf, ",");
736 u_strcat(buf, uw2);
737 ASSERT(strlen(buf) < sizeof_buf);
738 return buf;
739 }
740
741 #endif /* _DEVICE_TREE_C_ */