* cris/semcrisv32f-switch.c: Regenerate.
[deliverable/binutils-gdb.git] / sim / common / hw-base.c
CommitLineData
b85e4829
AC
1/* The common simulator framework for GDB, the GNU Debugger.
2
9b254dd1 3 Copyright 2002, 2007, 2008 Free Software Foundation, Inc.
b85e4829
AC
4
5 Contributed by Andrew Cagney and Red Hat.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
4744ac1b 11 the Free Software Foundation; either version 3 of the License, or
b85e4829
AC
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
4744ac1b 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
21
22
23#include "hw-main.h"
24#include "hw-base.h"
25
26
27#ifdef HAVE_STRING_H
28#include <string.h>
29#else
30#ifdef HAVE_STRINGS_H
31#include <strings.h>
32#endif
33#endif
34
35#if HAVE_STDLIB_H
36#include <stdlib.h>
37#endif
38
39#include <ctype.h>
40
41#include "hw-config.h"
42
43struct hw_base_data {
44 int finished_p;
45 const struct hw_descriptor *descriptor;
46 hw_delete_callback *to_delete;
47};
48
49static int
50generic_hw_unit_decode (struct hw *bus,
51 const char *unit,
52 hw_unit *phys)
53{
54 memset (phys, 0, sizeof (*phys));
55 if (unit == NULL)
56 return 0;
57 else
58 {
59 int nr_cells = 0;
60 const int max_nr_cells = hw_unit_nr_address_cells (bus);
61 while (1)
62 {
63 char *end = NULL;
64 unsigned long val;
65 val = strtoul (unit, &end, 0);
66 /* parse error? */
67 if (unit == end)
68 return -1;
69 /* two many cells? */
70 if (nr_cells >= max_nr_cells)
71 return -1;
72 /* save it */
73 phys->cells[nr_cells] = val;
74 nr_cells++;
75 unit = end;
76 /* more to follow? */
77 if (isspace (*unit) || *unit == '\0')
78 break;
79 if (*unit != ',')
80 return -1;
81 unit++;
82 }
83 if (nr_cells < max_nr_cells) {
84 /* shift everything to correct position */
85 int i;
86 for (i = 1; i <= nr_cells; i++)
87 phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
88 for (i = 0; i < (max_nr_cells - nr_cells); i++)
89 phys->cells[i] = 0;
90 }
91 phys->nr_cells = max_nr_cells;
92 return max_nr_cells;
93 }
94}
95
96static int
97generic_hw_unit_encode (struct hw *bus,
98 const hw_unit *phys,
99 char *buf,
100 int sizeof_buf)
101{
102 int i;
103 int len;
104 char *pos = buf;
105 /* skip leading zero's */
106 for (i = 0; i < phys->nr_cells; i++)
107 {
108 if (phys->cells[i] != 0)
109 break;
110 }
111 /* don't output anything if empty */
112 if (phys->nr_cells == 0)
113 {
114 strcpy(pos, "");
115 len = 0;
116 }
117 else if (i == phys->nr_cells)
118 {
119 /* all zero */
120 strcpy(pos, "0");
121 len = 1;
122 }
123 else
124 {
125 for (; i < phys->nr_cells; i++)
126 {
127 if (pos != buf) {
128 strcat(pos, ",");
129 pos = strchr(pos, '\0');
130 }
131 if (phys->cells[i] < 10)
132 sprintf (pos, "%ld", (unsigned long)phys->cells[i]);
133 else
134 sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]);
135 pos = strchr(pos, '\0');
136 }
137 len = pos - buf;
138 }
139 if (len >= sizeof_buf)
140 hw_abort (NULL, "generic_unit_encode - buffer overflow\n");
141 return len;
142}
143
144static int
145generic_hw_unit_address_to_attach_address (struct hw *me,
146 const hw_unit *address,
147 int *attach_space,
148 unsigned_word *attach_address,
149 struct hw *client)
150{
151 int i;
152 for (i = 0; i < address->nr_cells - 2; i++)
153 {
154 if (address->cells[i] != 0)
155 hw_abort (me, "Only 32bit addresses supported");
156 }
157 if (address->nr_cells >= 2)
158 *attach_space = address->cells[address->nr_cells - 2];
159 else
160 *attach_space = 0;
161 *attach_address = address->cells[address->nr_cells - 1];
162 return 1;
163}
164
165static int
166generic_hw_unit_size_to_attach_size (struct hw *me,
167 const hw_unit *size,
168 unsigned *nr_bytes,
169 struct hw *client)
170{
171 int i;
172 for (i = 0; i < size->nr_cells - 1; i++)
173 {
174 if (size->cells[i] != 0)
175 hw_abort (me, "Only 32bit sizes supported");
176 }
177 *nr_bytes = size->cells[0];
178 return *nr_bytes;
179}
180
181
182/* ignore/passthrough versions of each function */
183
184static void
185passthrough_hw_attach_address (struct hw *me,
186 int level,
187 int space,
188 address_word addr,
189 address_word nr_bytes,
190 struct hw *client) /*callback/default*/
191{
192 if (hw_parent (me) == NULL)
193 hw_abort (client, "hw_attach_address: no parent attach method");
194 hw_attach_address (hw_parent (me), level,
195 space, addr, nr_bytes,
196 client);
197}
198
199static void
200passthrough_hw_detach_address (struct hw *me,
201 int level,
202 int space,
203 address_word addr,
204 address_word nr_bytes,
205 struct hw *client) /*callback/default*/
206{
207 if (hw_parent (me) == NULL)
208 hw_abort (client, "hw_attach_address: no parent attach method");
209 hw_detach_address (hw_parent (me), level,
210 space, addr, nr_bytes,
211 client);
212}
213
214static unsigned
215panic_hw_io_read_buffer (struct hw *me,
216 void *dest,
217 int space,
218 unsigned_word addr,
219 unsigned nr_bytes)
220{
221 hw_abort (me, "no io-read method");
222 return 0;
223}
224
225static unsigned
226panic_hw_io_write_buffer (struct hw *me,
227 const void *source,
228 int space,
229 unsigned_word addr,
230 unsigned nr_bytes)
231{
232 hw_abort (me, "no io-write method");
233 return 0;
234}
235
236static unsigned
237passthrough_hw_dma_read_buffer (struct hw *me,
238 void *dest,
239 int space,
240 unsigned_word addr,
241 unsigned nr_bytes)
242{
243 if (hw_parent (me) == NULL)
244 hw_abort (me, "no parent dma-read method");
245 return hw_dma_read_buffer (hw_parent (me), dest,
246 space, addr, nr_bytes);
247}
248
249static unsigned
250passthrough_hw_dma_write_buffer (struct hw *me,
251 const void *source,
252 int space,
253 unsigned_word addr,
254 unsigned nr_bytes,
255 int violate_read_only_section)
256{
257 if (hw_parent (me) == NULL)
258 hw_abort (me, "no parent dma-write method");
259 return hw_dma_write_buffer (hw_parent (me), source,
260 space, addr,
261 nr_bytes,
262 violate_read_only_section);
263}
264
265static void
266ignore_hw_delete (struct hw *me)
267{
268 /* NOP */
269}
270
271
272
273
274static const char *
275full_name_of_hw (struct hw *leaf,
276 char *buf,
277 unsigned sizeof_buf)
278{
279 /* get a buffer */
280 char full_name[1024];
281 if (buf == (char*)0)
282 {
283 buf = full_name;
284 sizeof_buf = sizeof (full_name);
285 }
286
287 /* use head recursion to construct the path */
288
289 if (hw_parent (leaf) == NULL)
290 /* root */
291 {
292 if (sizeof_buf < 1)
293 hw_abort (leaf, "buffer overflow");
294 *buf = '\0';
295 }
296 else
297 /* sub node */
298 {
299 char unit[1024];
300 full_name_of_hw (hw_parent (leaf), buf, sizeof_buf);
301 if (hw_unit_encode (hw_parent (leaf),
302 hw_unit_address (leaf),
303 unit + 1,
304 sizeof (unit) - 1)
305 > 0)
306 unit[0] = '@';
307 else
308 unit[0] = '\0';
309 if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit)
310 >= sizeof_buf)
311 hw_abort (leaf, "buffer overflow");
312 strcat (buf, "/");
313 strcat (buf, hw_name (leaf));
314 strcat (buf, unit);
315 }
316
317 /* return it usefully */
318 if (buf == full_name)
319 buf = hw_strdup (leaf, full_name);
320 return buf;
321}
322
323struct hw *
324hw_create (struct sim_state *sd,
325 struct hw *parent,
326 const char *family,
327 const char *name,
328 const char *unit,
329 const char *args)
330{
331 /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */
332 struct hw *hw = ZALLOC (struct hw);
333
334 /* our identity */
335 hw->family_of_hw = hw_strdup (hw, family);
336 hw->name_of_hw = hw_strdup (hw, name);
337 hw->args_of_hw = hw_strdup (hw, args);
338
339 /* a hook into the system */
340 if (sd != NULL)
341 hw->system_of_hw = sd;
342 else if (parent != NULL)
343 hw->system_of_hw = hw_system (parent);
344 else
345 hw_abort (parent, "No system found");
346
347 /* in a tree */
348 if (parent != NULL)
349 {
350 struct hw **sibling = &parent->child_of_hw;
351 while ((*sibling) != NULL)
352 sibling = &(*sibling)->sibling_of_hw;
353 *sibling = hw;
354 hw->parent_of_hw = parent;
355 }
356
357 /* top of tree */
358 if (parent != NULL)
359 {
360 struct hw *root = parent;
361 while (root->parent_of_hw != NULL)
362 root = root->parent_of_hw;
363 hw->root_of_hw = root;
364 }
365
366 /* a unique identifier for the device on the parents bus */
367 if (parent != NULL)
368 {
369 hw_unit_decode (parent, unit, &hw->unit_address_of_hw);
370 }
371
372 /* Determine our path */
373 if (parent != NULL)
374 hw->path_of_hw = full_name_of_hw (hw, NULL, 0);
375 else
376 hw->path_of_hw = "/";
377
378 /* create our base type */
379 hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data);
380 hw->base_of_hw->finished_p = 0;
381
382 /* our callbacks */
383 set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
384 set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
385 set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer);
386 set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer);
387 set_hw_unit_decode (hw, generic_hw_unit_decode);
388 set_hw_unit_encode (hw, generic_hw_unit_encode);
389 set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address);
390 set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
391 set_hw_attach_address (hw, passthrough_hw_attach_address);
392 set_hw_detach_address (hw, passthrough_hw_detach_address);
393 set_hw_delete (hw, ignore_hw_delete);
394
395 /* locate a descriptor */
396 {
397 const struct hw_descriptor **table;
398 for (table = hw_descriptors;
399 *table != NULL;
400 table++)
401 {
402 const struct hw_descriptor *entry;
403 for (entry = *table;
404 entry->family != NULL;
405 entry++)
406 {
407 if (strcmp (family, entry->family) == 0)
408 {
409 hw->base_of_hw->descriptor = entry;
410 break;
411 }
412 }
413 }
414 if (hw->base_of_hw->descriptor == NULL)
415 {
416 hw_abort (parent, "Unknown device `%s'", family);
417 }
418 }
419
420 /* Attach dummy ports */
421 create_hw_alloc_data (hw);
422 create_hw_property_data (hw);
423 create_hw_port_data (hw);
424 create_hw_event_data (hw);
425 create_hw_handle_data (hw);
426 create_hw_instance_data (hw);
427
428 return hw;
429}
430
431
432int
433hw_finished_p (struct hw *me)
434{
435 return (me->base_of_hw->finished_p);
436}
437
438void
439hw_finish (struct hw *me)
440{
441 if (hw_finished_p (me))
442 hw_abort (me, "Attempt to finish finished device");
443
444 /* Fill in the (hopefully) defined address/size cells values */
445 if (hw_find_property (me, "#address-cells") != NULL)
446 me->nr_address_cells_of_hw_unit =
447 hw_find_integer_property (me, "#address-cells");
448 else
449 me->nr_address_cells_of_hw_unit = 2;
450 if (hw_find_property (me, "#size-cells") != NULL)
451 me->nr_size_cells_of_hw_unit =
452 hw_find_integer_property (me, "#size-cells");
453 else
454 me->nr_size_cells_of_hw_unit = 1;
455
456 /* Fill in the (hopefully) defined trace variable */
457 if (hw_find_property (me, "trace?") != NULL)
458 me->trace_of_hw_p = hw_find_boolean_property (me, "trace?");
459 /* allow global variable to define default tracing */
460 else if (! hw_trace_p (me)
461 && hw_find_property (hw_root (me), "global-trace?") != NULL
462 && hw_find_boolean_property (hw_root (me), "global-trace?"))
463 me->trace_of_hw_p = 1;
464
465
466 /* Allow the real device to override any methods */
467 me->base_of_hw->descriptor->to_finish (me);
468 me->base_of_hw->finished_p = 1;
469}
470
471
472void
473hw_delete (struct hw *me)
474{
475 /* give the object a chance to tidy up */
476 me->base_of_hw->to_delete (me);
477
478 delete_hw_instance_data (me);
479 delete_hw_handle_data (me);
480 delete_hw_event_data (me);
481 delete_hw_port_data (me);
482 delete_hw_property_data (me);
483
484 /* now unlink us from the tree */
485 if (hw_parent (me))
486 {
487 struct hw **sibling = &hw_parent (me)->child_of_hw;
488 while (*sibling != NULL)
489 {
490 if (*sibling == me)
491 {
492 *sibling = me->sibling_of_hw;
493 me->sibling_of_hw = NULL;
494 me->parent_of_hw = NULL;
495 break;
496 }
497 }
498 }
499
500 /* some sanity checks */
501 if (hw_child (me) != NULL)
502 {
503 hw_abort (me, "attempt to delete device with children");
504 }
505 if (hw_sibling (me) != NULL)
506 {
507 hw_abort (me, "attempt to delete device with siblings");
508 }
509
510 /* blow away all memory belonging to the device */
511 delete_hw_alloc_data (me);
512
513 /* finally */
c906108c
SS
514 zfree (me);
515}
516
ce13044d
SC
517void
518set_hw_delete (struct hw *hw, hw_delete_callback method)
519{
520 hw->base_of_hw->to_delete = method;
521}
522
c906108c
SS
523
524/* Go through the devices various reg properties for those that
525 specify attach addresses */
526
527
528void
529do_hw_attach_regs (struct hw *hw)
530{
531 static const char *(reg_property_names[]) = {
532 "attach-addresses",
533 "assigned-addresses",
534 "reg",
535 "alternate-reg" ,
536 NULL
537 };
538 const char **reg_property_name;
539 int nr_valid_reg_properties = 0;
540 for (reg_property_name = reg_property_names;
541 *reg_property_name != NULL;
542 reg_property_name++)
543 {
544 if (hw_find_property (hw, *reg_property_name) != NULL)
545 {
546 reg_property_spec reg;
547 int reg_entry;
548 for (reg_entry = 0;
549 hw_find_reg_array_property (hw, *reg_property_name, reg_entry,
550 &reg);
551 reg_entry++)
552 {
553 unsigned_word attach_address;
554 int attach_space;
555 unsigned attach_size;
556 if (!hw_unit_address_to_attach_address (hw_parent (hw),
557 &reg.address,
558 &attach_space,
559 &attach_address,
560 hw))
561 continue;
562 if (!hw_unit_size_to_attach_size (hw_parent (hw),
563 &reg.size,
564 &attach_size, hw))
565 continue;
566 hw_attach_address (hw_parent (hw),
567 0,
568 attach_space, attach_address, attach_size,
569 hw);
570 nr_valid_reg_properties++;
571 }
572 /* if first option matches don't try for any others */
573 if (reg_property_name == reg_property_names)
574 break;
575 }
576 }
577}
This page took 0.408391 seconds and 4 git commands to generate.