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