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