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