sim: hw: localize init callback
[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 char *device_path = NULL;
142 size_t buf_size = 0;
143 ssize_t device_path_len;
144
145 /* try opening the file */
146 description = fopen (file_name, "r");
147 if (description == NULL)
148 {
149 perror (file_name);
150 return SIM_RC_FAIL;
151 }
152
153 while ((device_path_len = getline (&device_path, &buf_size, description)) > 0)
154 {
155 char *device;
156 char *next_line = NULL;
157
158 if (device_path[device_path_len - 1] == '\n')
159 device_path[--device_path_len] = '\0';
160
161 /* skip comments ("#" or ";") and blank lines lines */
162 for (device = device_path;
163 *device != '\0' && isspace (*device);
164 device++);
165 if (device[0] == '#'
166 || device[0] == ';'
167 || device[0] == '\0')
168 continue;
169
170 /* merge any appended lines */
171 while (device_path[device_path_len - 1] == '\\')
172 {
173 size_t next_buf_size = 0;
174 ssize_t next_line_len;
175
176 /* zap the `\' at the end of the line */
177 device_path[--device_path_len] = '\0';
178
179 /* get the next line */
180 next_line_len = getline (&next_line, &next_buf_size, description);
181 if (next_line_len <= 0)
182 break;
183
184 if (next_line[next_line_len - 1] == '\n')
185 next_line[--next_line_len] = '\0';
186
187 /* append the next line */
188 if (buf_size - device_path_len <= next_line_len)
189 {
190 ptrdiff_t offset = device - device_path;
191
192 buf_size += next_buf_size;
193 device_path = xrealloc (device_path, buf_size);
194 device = device_path + offset;
195 }
196 memcpy (device_path + device_path_len, next_line,
197 next_line_len + 1);
198 device_path_len += next_line_len;
199 }
200 free (next_line);
201
202 /* parse this line */
203 current = hw_tree_parse (current, "%s", device);
204 }
205
206 free (device_path);
207 fclose (description);
208 return SIM_RC_OK;
209 }
210
211
212 static SIM_RC
213 hw_option_handler (struct sim_state *sd, sim_cpu *cpu, int opt,
214 char *arg, int is_command)
215 {
216 switch (opt)
217 {
218
219 case OPTION_HW_INFO:
220 {
221 /* delay info until after the tree is finished */
222 STATE_HW (sd)->info_p = 1;
223 return SIM_RC_OK;
224 break;
225 }
226
227 case OPTION_HW_TRACE:
228 {
229 if (arg == NULL)
230 {
231 STATE_HW (sd)->trace_p = 1;
232 }
233 else if (strcmp (arg, "yes") == 0
234 || strcmp (arg, "on") == 0)
235 {
236 STATE_HW (sd)->trace_p = 1;
237 }
238 else if (strcmp (arg, "no") == 0
239 || strcmp (arg, "off") == 0)
240 {
241 STATE_HW (sd)->trace_p = 0;
242 }
243 else
244 {
245 sim_io_eprintf (sd, "Option --hw-trace ignored\n");
246 /* set tracing on all devices */
247 return SIM_RC_FAIL;
248 }
249 /* FIXME: Not very nice - see also hw-base.c */
250 if (STATE_HW (sd)->trace_p)
251 hw_tree_parse (STATE_HW (sd)->tree, "/global-trace? true");
252 return SIM_RC_OK;
253 break;
254 }
255
256 case OPTION_HW_DEVICE:
257 {
258 hw_tree_parse (STATE_HW (sd)->tree, "%s", arg);
259 return SIM_RC_OK;
260 }
261
262 case OPTION_HW_LIST:
263 {
264 sim_hw_print (sd, sim_io_vprintf);
265 return SIM_RC_OK;
266 }
267
268 case OPTION_HW_FILE:
269 {
270 return merge_device_file (sd, arg);
271 }
272
273 default:
274 sim_io_eprintf (sd, "Unknown hw option %d\n", opt);
275 return SIM_RC_FAIL;
276
277 }
278
279 return SIM_RC_FAIL;
280 }
281
282
283 /* "hw" module install handler.
284
285 This is called via sim_module_install to install the "hw" subsystem
286 into the simulator. */
287
288 static MODULE_INIT_FN sim_hw_init;
289 static MODULE_UNINSTALL_FN sim_hw_uninstall;
290
291 /* Provide a prototype to silence -Wmissing-prototypes. */
292 SIM_RC sim_install_hw (struct sim_state *sd);
293
294 /* Establish this object. */
295 SIM_RC
296 sim_install_hw (struct sim_state *sd)
297 {
298 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
299 sim_add_option_table (sd, NULL, hw_options);
300 sim_module_add_uninstall_fn (sd, sim_hw_uninstall);
301 sim_module_add_init_fn (sd, sim_hw_init);
302 STATE_HW (sd) = ZALLOC (struct sim_hw);
303 STATE_HW (sd)->tree = hw_tree_create (sd, "core");
304 return SIM_RC_OK;
305 }
306
307
308 static SIM_RC
309 sim_hw_init (struct sim_state *sd)
310 {
311 /* FIXME: anything needed? */
312 hw_tree_finish (STATE_HW (sd)->tree);
313 if (STATE_HW (sd)->info_p)
314 sim_hw_print (sd, sim_io_vprintf);
315 return SIM_RC_OK;
316 }
317
318 /* Uninstall the "hw" subsystem from the simulator. */
319
320 static void
321 sim_hw_uninstall (struct sim_state *sd)
322 {
323 hw_tree_delete (STATE_HW (sd)->tree);
324 free (STATE_HW (sd));
325 STATE_HW (sd) = NULL;
326 }
327
328
329 \f
330 /* Data transfers to/from the hardware device tree. There are several
331 cases. */
332
333
334 /* CPU: The simulation is running and the current CPU/CIA
335 initiates a data transfer. */
336
337 void
338 sim_cpu_hw_io_read_buffer (sim_cpu *cpu,
339 sim_cia cia,
340 struct hw *hw,
341 void *dest,
342 int space,
343 unsigned_word addr,
344 unsigned nr_bytes)
345 {
346 SIM_DESC sd = CPU_STATE (cpu);
347 STATE_HW (sd)->cpu = cpu;
348 STATE_HW (sd)->cia = cia;
349 if (hw_io_read_buffer (hw, dest, space, addr, nr_bytes) != nr_bytes)
350 sim_engine_abort (sd, cpu, cia, "broken CPU read");
351 }
352
353 void
354 sim_cpu_hw_io_write_buffer (sim_cpu *cpu,
355 sim_cia cia,
356 struct hw *hw,
357 const void *source,
358 int space,
359 unsigned_word addr,
360 unsigned nr_bytes)
361 {
362 SIM_DESC sd = CPU_STATE (cpu);
363 STATE_HW (sd)->cpu = cpu;
364 STATE_HW (sd)->cia = cia;
365 if (hw_io_write_buffer (hw, source, space, addr, nr_bytes) != nr_bytes)
366 sim_engine_abort (sd, cpu, cia, "broken CPU write");
367 }
368
369
370
371
372 /* SYSTEM: A data transfer is being initiated by the system. */
373
374 unsigned
375 sim_hw_io_read_buffer (struct sim_state *sd,
376 struct hw *hw,
377 void *dest,
378 int space,
379 unsigned_word addr,
380 unsigned nr_bytes)
381 {
382 STATE_HW (sd)->cpu = NULL;
383 return hw_io_read_buffer (hw, dest, space, addr, nr_bytes);
384 }
385
386 unsigned
387 sim_hw_io_write_buffer (struct sim_state *sd,
388 struct hw *hw,
389 const void *source,
390 int space,
391 unsigned_word addr,
392 unsigned nr_bytes)
393 {
394 STATE_HW (sd)->cpu = NULL;
395 return hw_io_write_buffer (hw, source, space, addr, nr_bytes);
396 }
397
398
399 \f
400 /* Abort the simulation specifying HW as the reason */
401
402 void
403 hw_vabort (struct hw *me,
404 const char *fmt,
405 va_list ap)
406 {
407 const char *name;
408 char *msg;
409 /* find an identity */
410 if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0')
411 name = hw_path (me);
412 else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0')
413 name = hw_name (me);
414 else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0')
415 name = hw_family (me);
416 else
417 name = "device";
418 /* construct an updated format string */
419 msg = alloca (strlen (name) + strlen (": ") + strlen (fmt) + 1);
420 strcpy (msg, name);
421 strcat (msg, ": ");
422 strcat (msg, fmt);
423 /* report the problem */
424 sim_engine_vabort (hw_system (me),
425 STATE_HW (hw_system (me))->cpu,
426 STATE_HW (hw_system (me))->cia,
427 msg, ap);
428 }
429
430 void
431 hw_abort (struct hw *me,
432 const char *fmt,
433 ...)
434 {
435 va_list ap;
436 /* report the problem */
437 va_start (ap, fmt);
438 hw_vabort (me, fmt, ap);
439 va_end (ap);
440 }
441
442 void
443 sim_hw_abort (struct sim_state *sd,
444 struct hw *me,
445 const char *fmt,
446 ...)
447 {
448 va_list ap;
449 va_start (ap, fmt);
450 if (me == NULL)
451 sim_engine_vabort (sd, NULL, NULL_CIA, fmt, ap);
452 else
453 hw_vabort (me, fmt, ap);
454 va_end (ap);
455 }
456
457
458 /* MISC routines to tie HW into the rest of the system */
459
460 void
461 hw_halt (struct hw *me,
462 int reason,
463 int status)
464 {
465 struct sim_state *sd = hw_system (me);
466 struct sim_hw *sim = STATE_HW (sd);
467 sim_engine_halt (sd, sim->cpu, NULL, sim->cia, reason, status);
468 }
469
470 struct _sim_cpu *
471 hw_system_cpu (struct hw *me)
472 {
473 return STATE_HW (hw_system (me))->cpu;
474 }
475
476 void
477 hw_trace (struct hw *me,
478 const char *fmt,
479 ...)
480 {
481 if (hw_trace_p (me)) /* to be sure, to be sure */
482 {
483 va_list ap;
484 va_start (ap, fmt);
485 sim_io_eprintf (hw_system (me), "%s: ", hw_path (me));
486 sim_io_evprintf (hw_system (me), fmt, ap);
487 sim_io_eprintf (hw_system (me), "\n");
488 va_end (ap);
489 }
490 }
491
492
493 /* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */
494
495 int
496 do_hw_poll_read (struct hw *me,
497 do_hw_poll_read_method *read,
498 int sim_io_fd,
499 void *buf,
500 unsigned sizeof_buf)
501 {
502 int status = read (hw_system (me), sim_io_fd, buf, sizeof_buf);
503 if (status > 0)
504 return status;
505 else if (status == 0 && sizeof_buf == 0)
506 return 0;
507 else if (status == 0)
508 return HW_IO_EOF;
509 else /* status < 0 */
510 {
511 #ifdef EAGAIN
512 if (STATE_CALLBACK (hw_system (me))->last_errno == EAGAIN)
513 return HW_IO_NOT_READY;
514 else
515 return HW_IO_EOF;
516 #else
517 return HW_IO_EOF;
518 #endif
519 }
520 }
This page took 0.050949 seconds and 5 git commands to generate.