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