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