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