]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/sim-hw.c
922b8ec44afc6a6f3f5fe8767a1220c82f792ba6
[thirdparty/binutils-gdb.git] / sim / common / sim-hw.c
1 /* Simulator hardware option handling.
2 Copyright (C) 1998 Free Software Foundation, Inc.
3 Contributed by Cygnus Support and Andrew Cagney.
4
5 This file is part of GDB, the GNU debugger.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #include "sim-main.h"
22 #include "sim-assert.h"
23 #include "sim-options.h"
24
25 #include "sim-hw.h"
26
27 #include "hw-tree.h"
28 #include "hw-device.h"
29 #include "hw-main.h"
30 #include "hw-base.h"
31
32
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #else
36 #ifdef HAVE_STRINGS_H
37 #include <strings.h>
38 #endif
39 #endif
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43 #include <ctype.h>
44 #include <errno.h>
45
46
47 struct sim_hw {
48 struct hw *tree;
49 int trace_p;
50 int info_p;
51 /* if called from a processor */
52 sim_cpu *cpu;
53 sim_cia cia;
54 };
55
56
57 struct hw *
58 sim_hw_parse (struct sim_state *sd,
59 const char *fmt,
60 ...)
61 {
62 struct hw *current;
63 va_list ap;
64 va_start (ap, fmt);
65 current = hw_tree_vparse (STATE_HW (sd)->tree, fmt, ap);
66 va_end (ap);
67 return current;
68 }
69
70 struct printer {
71 struct sim_state *file;
72 void (*print) (struct sim_state *, const char *, va_list ap);
73 };
74
75 static void
76 do_print (void *file, const char *fmt, ...)
77 {
78 struct printer *p = file;
79 va_list ap;
80 va_start (ap, fmt);
81 p->print (p->file, fmt, ap);
82 va_end (ap);
83 }
84
85 void
86 sim_hw_print (struct sim_state *sd,
87 void (*print) (struct sim_state *, const char *, va_list ap))
88 {
89 struct printer p;
90 p.file = sd;
91 p.print = print;
92 hw_tree_print (STATE_HW (sd)->tree, do_print, &p);
93 }
94
95
96
97
98 /* command line options. */
99
100 enum {
101 OPTION_HW_INFO = OPTION_START,
102 OPTION_HW_TRACE,
103 OPTION_HW_DEVICE,
104 OPTION_HW_LIST,
105 OPTION_HW_FILE,
106 };
107
108 static DECLARE_OPTION_HANDLER (hw_option_handler);
109
110 static const OPTION hw_options[] =
111 {
112 { {"hw-info", no_argument, NULL, OPTION_HW_INFO },
113 '\0', NULL, "List configurable hw regions",
114 hw_option_handler },
115 { {"info-hw", no_argument, NULL, OPTION_HW_INFO },
116 '\0', NULL, NULL,
117 hw_option_handler },
118
119 { {"hw-trace", optional_argument, NULL, OPTION_HW_TRACE },
120 '\0', "on|off", "Trace all hardware devices",
121 hw_option_handler },
122 { {"trace-hw", optional_argument, NULL, OPTION_HW_TRACE },
123 '\0', NULL, NULL,
124 hw_option_handler },
125
126 { {"hw-device", required_argument, NULL, OPTION_HW_DEVICE },
127 '\0', "DEVICE", "Add the specified device",
128 hw_option_handler },
129
130 { {"hw-list", no_argument, NULL, OPTION_HW_LIST },
131 '\0', NULL, "List the device tree",
132 hw_option_handler },
133
134 { {"hw-file", required_argument, NULL, OPTION_HW_FILE },
135 '\0', "FILE", "Add the devices listed in the file",
136 hw_option_handler },
137
138 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
139 };
140
141
142
143 /* Copied from ../ppc/psim.c:psim_merge_device_file() */
144
145 static SIM_RC
146 merge_device_file (struct sim_state *sd,
147 const char *file_name)
148 {
149 FILE *description;
150 struct hw *current = STATE_HW (sd)->tree;
151 int line_nr;
152 char device_path[1000];
153
154 /* try opening the file */
155 description = fopen (file_name, "r");
156 if (description == NULL)
157 {
158 perror (file_name);
159 return SIM_RC_FAIL;
160 }
161
162 line_nr = 0;
163 while (fgets (device_path, sizeof(device_path), description))
164 {
165 char *device;
166 /* check that a complete line was read */
167 if (strchr (device_path, '\n') == NULL)
168 {
169 fclose (description);
170 sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr);
171 return SIM_RC_FAIL;
172 }
173 *strchr (device_path, '\n') = '\0';
174 line_nr++;
175 /* skip comments ("#" or ";") and blank lines lines */
176 for (device = device_path;
177 *device != '\0' && isspace (*device);
178 device++);
179 if (device[0] == '#'
180 || device[0] == ';'
181 || device[0] == '\0')
182 continue;
183 /* merge any appended lines */
184 while (device_path[strlen (device_path) - 1] == '\\')
185 {
186 int curlen = strlen (device_path) - 1;
187 /* zap the `\' at the end of the line */
188 device_path[curlen] = '\0';
189 /* append the next line */
190 if (!fgets (device_path + curlen,
191 sizeof (device_path) - curlen,
192 description))
193 {
194 fclose (description);
195 sim_io_eprintf (sd, "%s:%d: unexpected eof", file_name, line_nr);
196 return SIM_RC_FAIL;
197 }
198 if (strchr(device_path, '\n') == NULL)
199 {
200 fclose(description);
201 sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr);
202 return SIM_RC_FAIL;
203 }
204 *strchr(device_path, '\n') = '\0';
205 line_nr++;
206 }
207 /* parse this line */
208 current = hw_tree_parse (current, "%s", device);
209 }
210 fclose (description);
211 return SIM_RC_OK;
212 }
213
214
215 static SIM_RC
216 hw_option_handler (struct sim_state *sd, sim_cpu *cpu, int opt,
217 char *arg, int is_command)
218 {
219 switch (opt)
220 {
221
222 case OPTION_HW_INFO:
223 {
224 /* delay info until after the tree is finished */
225 STATE_HW (sd)->info_p = 1;
226 return SIM_RC_OK;
227 break;
228 }
229
230 case OPTION_HW_TRACE:
231 {
232 if (arg == NULL)
233 {
234 STATE_HW (sd)->trace_p = 1;
235 }
236 else if (strcmp (arg, "yes") == 0
237 || strcmp (arg, "on") == 0)
238 {
239 STATE_HW (sd)->trace_p = 1;
240 }
241 else if (strcmp (arg, "no") == 0
242 || strcmp (arg, "off") == 0)
243 {
244 STATE_HW (sd)->trace_p = 0;
245 }
246 else
247 {
248 sim_io_eprintf (sd, "Option --hw-trace ignored\n");
249 /* set tracing on all devices */
250 return SIM_RC_FAIL;
251 }
252 /* FIXME: Not very nice - see also hw-base.c */
253 if (STATE_HW (sd)->trace_p)
254 hw_tree_parse (STATE_HW (sd)->tree, "/global-trace? true");
255 return SIM_RC_OK;
256 break;
257 }
258
259 case OPTION_HW_DEVICE:
260 {
261 hw_tree_parse (STATE_HW (sd)->tree, arg);
262 return SIM_RC_OK;
263 }
264
265 case OPTION_HW_LIST:
266 {
267 sim_hw_print (sd, sim_io_vprintf);
268 return SIM_RC_OK;
269 }
270
271 case OPTION_HW_FILE:
272 {
273 return merge_device_file (sd, arg);
274 }
275
276 default:
277 sim_io_eprintf (sd, "Unknown hw option %d\n", opt);
278 return SIM_RC_FAIL;
279
280 }
281
282 return SIM_RC_FAIL;
283 }
284
285
286 /* "hw" module install handler.
287
288 This is called via sim_module_install to install the "hw" subsystem
289 into the simulator. */
290
291 static MODULE_INIT_FN sim_hw_init;
292 static MODULE_UNINSTALL_FN sim_hw_uninstall;
293
294 SIM_RC
295 sim_hw_install (struct sim_state *sd)
296 {
297 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
298 sim_add_option_table (sd, NULL, hw_options);
299 sim_module_add_uninstall_fn (sd, sim_hw_uninstall);
300 sim_module_add_init_fn (sd, sim_hw_init);
301 STATE_HW (sd) = ZALLOC (struct sim_hw);
302 STATE_HW (sd)->tree = hw_tree_create (sd, "core");
303 return SIM_RC_OK;
304 }
305
306
307 static SIM_RC
308 sim_hw_init (struct sim_state *sd)
309 {
310 /* FIXME: anything needed? */
311 hw_tree_finish (STATE_HW (sd)->tree);
312 if (STATE_HW (sd)->info_p)
313 sim_hw_print (sd, sim_io_vprintf);
314 return SIM_RC_OK;
315 }
316
317 /* Uninstall the "hw" subsystem from the simulator. */
318
319 static void
320 sim_hw_uninstall (struct sim_state *sd)
321 {
322 /* hw_tree_delete (STATE_HW (sd)->tree); */
323 zfree (STATE_HW (sd));
324 STATE_HW (sd) = NULL;
325 }
326
327
328 \f
329 /* Data transfers to/from the hardware device tree. There are several
330 cases. */
331
332
333 /* CPU: The simulation is running and the current CPU/CIA
334 initiates a data transfer. */
335
336 void
337 sim_cpu_hw_io_read_buffer (sim_cpu *cpu,
338 sim_cia cia,
339 struct hw *hw,
340 void *dest,
341 int space,
342 unsigned_word addr,
343 unsigned nr_bytes)
344 {
345 SIM_DESC sd = CPU_STATE (cpu);
346 STATE_HW (sd)->cpu = cpu;
347 STATE_HW (sd)->cia = cia;
348 if (hw_io_read_buffer (hw, dest, space, addr, nr_bytes) != nr_bytes)
349 sim_engine_abort (sd, cpu, cia, "broken CPU read");
350 }
351
352 void
353 sim_cpu_hw_io_write_buffer (sim_cpu *cpu,
354 sim_cia cia,
355 struct hw *hw,
356 const void *source,
357 int space,
358 unsigned_word addr,
359 unsigned nr_bytes)
360 {
361 SIM_DESC sd = CPU_STATE (cpu);
362 STATE_HW (sd)->cpu = cpu;
363 STATE_HW (sd)->cia = cia;
364 if (hw_io_write_buffer (hw, source, space, addr, nr_bytes) != nr_bytes)
365 sim_engine_abort (sd, cpu, cia, "broken CPU write");
366 }
367
368
369
370
371 /* SYSTEM: A data transfer is being initiated by the system. */
372
373 unsigned
374 sim_hw_io_read_buffer (struct sim_state *sd,
375 struct hw *hw,
376 void *dest,
377 int space,
378 unsigned_word addr,
379 unsigned nr_bytes)
380 {
381 STATE_HW (sd)->cpu = NULL;
382 return hw_io_read_buffer (hw, dest, space, addr, nr_bytes);
383 }
384
385 unsigned
386 sim_hw_io_write_buffer (struct sim_state *sd,
387 struct hw *hw,
388 const void *source,
389 int space,
390 unsigned_word addr,
391 unsigned nr_bytes)
392 {
393 STATE_HW (sd)->cpu = NULL;
394 return hw_io_write_buffer (hw, source, space, addr, nr_bytes);
395 }
396
397
398 \f
399 /* Abort the simulation specifying HW as the reason */
400
401 void
402 hw_vabort (struct hw *me,
403 const char *fmt,
404 va_list ap)
405 {
406 const char *name;
407 char *msg;
408 /* find an identity */
409 if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0')
410 name = hw_path (me);
411 else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0')
412 name = hw_name (me);
413 else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0')
414 name = hw_family (me);
415 else
416 name = "device";
417 /* construct an updated format string */
418 msg = alloca (strlen (name) + strlen (": ") + strlen (fmt) + 1);
419 strcpy (msg, name);
420 strcat (msg, ": ");
421 strcat (msg, fmt);
422 /* report the problem */
423 sim_engine_vabort (hw_system (me),
424 STATE_HW (hw_system (me))->cpu,
425 STATE_HW (hw_system (me))->cia,
426 msg, ap);
427 }
428
429 void
430 hw_abort (struct hw *me,
431 const char *fmt,
432 ...)
433 {
434 va_list ap;
435 /* report the problem */
436 va_start (ap, fmt);
437 hw_vabort (me, fmt, ap);
438 va_end (ap);
439 }
440
441 void
442 sim_hw_abort (struct sim_state *sd,
443 struct hw *me,
444 const char *fmt,
445 ...)
446 {
447 va_list ap;
448 va_start (ap, fmt);
449 if (me == NULL)
450 sim_engine_vabort (sd, NULL, NULL_CIA, fmt, ap);
451 else
452 hw_vabort (me, fmt, ap);
453 va_end (ap);
454 }
455
456
457 /* MISC routines to tie HW into the rest of the system */
458
459 void
460 hw_halt (struct hw *me,
461 int reason,
462 int status)
463 {
464 struct sim_state *sd = hw_system (me);
465 struct sim_hw *sim = STATE_HW (sd);
466 sim_engine_halt (sd, sim->cpu, NULL, sim->cia, reason, status);
467 }
468
469 struct _sim_cpu *
470 hw_system_cpu (struct hw *me)
471 {
472 return STATE_HW (hw_system (me))->cpu;
473 }
474
475 void
476 hw_trace (struct hw *me,
477 const char *fmt,
478 ...)
479 {
480 if (hw_trace_p (me)) /* to be sure, to be sure */
481 {
482 va_list ap;
483 va_start (ap, fmt);
484 sim_io_eprintf (hw_system (me), "%s: ", hw_path (me));
485 sim_io_evprintf (hw_system (me), fmt, ap);
486 sim_io_eprintf (hw_system (me), "\n");
487 va_end (ap);
488 }
489 }
490
491
492 /* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */
493
494 int
495 do_hw_poll_read (struct hw *me,
496 do_hw_poll_read_method *read,
497 int sim_io_fd,
498 void *buf,
499 unsigned sizeof_buf)
500 {
501 int status = read (hw_system (me), sim_io_fd, buf, sizeof_buf);
502 if (status > 0)
503 return status;
504 else if (status == 0 && sizeof_buf == 0)
505 return 0;
506 else if (status == 0)
507 return HW_IO_EOF;
508 else /* status < 0 */
509 {
510 #ifdef EAGAIN
511 if (STATE_CALLBACK (hw_system (me))->last_errno == EAGAIN)
512 return HW_IO_NOT_READY;
513 else
514 return HW_IO_EOF;
515 #else
516 return HW_IO_EOF;
517 #endif
518 }
519 }