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