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