]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/sim-hw.c
sim: switch config.h usage to defs.h
[thirdparty/binutils-gdb.git] / sim / common / sim-hw.c
CommitLineData
c906108c 1/* Simulator hardware option handling.
3666a048 2 Copyright (C) 1998-2021 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"
26
27#include "sim-hw.h"
28
29#include "hw-tree.h"
30#include "hw-device.h"
31#include "hw-main.h"
32#include "hw-base.h"
33
c906108c 34#include <string.h>
c906108c 35#include <stdlib.h>
c906108c 36#include <ctype.h>
0802cc40 37#include <errno.h>
c906108c
SS
38
39
40struct sim_hw {
41 struct hw *tree;
42 int trace_p;
43 int info_p;
44 /* if called from a processor */
45 sim_cpu *cpu;
46 sim_cia cia;
47};
48
49
50struct hw *
51sim_hw_parse (struct sim_state *sd,
52 const char *fmt,
53 ...)
54{
55 struct hw *current;
56 va_list ap;
57 va_start (ap, fmt);
58 current = hw_tree_vparse (STATE_HW (sd)->tree, fmt, ap);
59 va_end (ap);
60 return current;
61}
62
63struct printer {
64 struct sim_state *file;
65 void (*print) (struct sim_state *, const char *, va_list ap);
66};
67
68static void
69do_print (void *file, const char *fmt, ...)
70{
71 struct printer *p = file;
72 va_list ap;
73 va_start (ap, fmt);
74 p->print (p->file, fmt, ap);
75 va_end (ap);
76}
77
78void
79sim_hw_print (struct sim_state *sd,
80 void (*print) (struct sim_state *, const char *, va_list ap))
81{
82 struct printer p;
83 p.file = sd;
84 p.print = print;
85 hw_tree_print (STATE_HW (sd)->tree, do_print, &p);
86}
87
88
89
90
91/* command line options. */
92
93enum {
94 OPTION_HW_INFO = OPTION_START,
95 OPTION_HW_TRACE,
96 OPTION_HW_DEVICE,
0802cc40 97 OPTION_HW_LIST,
c906108c
SS
98 OPTION_HW_FILE,
99};
100
101static DECLARE_OPTION_HANDLER (hw_option_handler);
102
103static const OPTION hw_options[] =
104{
105 { {"hw-info", no_argument, NULL, OPTION_HW_INFO },
106 '\0', NULL, "List configurable hw regions",
21cf617c 107 hw_option_handler, NULL },
c906108c
SS
108 { {"info-hw", no_argument, NULL, OPTION_HW_INFO },
109 '\0', NULL, NULL,
21cf617c 110 hw_option_handler, NULL },
c906108c
SS
111
112 { {"hw-trace", optional_argument, NULL, OPTION_HW_TRACE },
113 '\0', "on|off", "Trace all hardware devices",
21cf617c 114 hw_option_handler, NULL },
c906108c
SS
115 { {"trace-hw", optional_argument, NULL, OPTION_HW_TRACE },
116 '\0', NULL, NULL,
21cf617c 117 hw_option_handler, NULL },
c906108c
SS
118
119 { {"hw-device", required_argument, NULL, OPTION_HW_DEVICE },
120 '\0', "DEVICE", "Add the specified device",
21cf617c 121 hw_option_handler, NULL },
c906108c 122
0802cc40
AC
123 { {"hw-list", no_argument, NULL, OPTION_HW_LIST },
124 '\0', NULL, "List the device tree",
21cf617c 125 hw_option_handler, NULL },
0802cc40 126
c906108c
SS
127 { {"hw-file", required_argument, NULL, OPTION_HW_FILE },
128 '\0', "FILE", "Add the devices listed in the file",
21cf617c 129 hw_option_handler, NULL },
c906108c 130
21cf617c 131 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
c906108c
SS
132};
133
134
135
136/* Copied from ../ppc/psim.c:psim_merge_device_file() */
137
138static SIM_RC
139merge_device_file (struct sim_state *sd,
140 const char *file_name)
141{
142 FILE *description;
143 struct hw *current = STATE_HW (sd)->tree;
f4dd7491
MF
144 char *device_path = NULL;
145 size_t buf_size = 0;
146 ssize_t device_path_len;
028f6515 147
c906108c
SS
148 /* try opening the file */
149 description = fopen (file_name, "r");
150 if (description == NULL)
151 {
152 perror (file_name);
153 return SIM_RC_FAIL;
154 }
028f6515 155
f4dd7491 156 while ((device_path_len = getline (&device_path, &buf_size, description)) > 0)
c906108c
SS
157 {
158 char *device;
f4dd7491
MF
159 char *next_line = NULL;
160
161 if (device_path[device_path_len - 1] == '\n')
162 device_path[--device_path_len] = '\0';
163
c906108c
SS
164 /* skip comments ("#" or ";") and blank lines lines */
165 for (device = device_path;
166 *device != '\0' && isspace (*device);
167 device++);
168 if (device[0] == '#'
169 || device[0] == ';'
170 || device[0] == '\0')
171 continue;
f4dd7491 172
c906108c 173 /* merge any appended lines */
f4dd7491 174 while (device_path[device_path_len - 1] == '\\')
c906108c 175 {
f4dd7491
MF
176 size_t next_buf_size = 0;
177 ssize_t next_line_len;
178
c906108c 179 /* zap the `\' at the end of the line */
f4dd7491
MF
180 device_path[--device_path_len] = '\0';
181
182 /* get the next line */
183 next_line_len = getline (&next_line, &next_buf_size, description);
184 if (next_line_len <= 0)
185 break;
186
187 if (next_line[next_line_len - 1] == '\n')
188 next_line[--next_line_len] = '\0';
189
c906108c 190 /* append the next line */
f4dd7491 191 if (buf_size - device_path_len <= next_line_len)
c906108c 192 {
f4dd7491
MF
193 ptrdiff_t offset = device - device_path;
194
195 buf_size += next_buf_size;
196 device_path = xrealloc (device_path, buf_size);
197 device = device_path + offset;
c906108c 198 }
f4dd7491
MF
199 memcpy (device_path + device_path_len, next_line,
200 next_line_len + 1);
201 device_path_len += next_line_len;
c906108c 202 }
f4dd7491
MF
203 free (next_line);
204
c906108c
SS
205 /* parse this line */
206 current = hw_tree_parse (current, "%s", device);
207 }
f4dd7491
MF
208
209 free (device_path);
c906108c
SS
210 fclose (description);
211 return SIM_RC_OK;
212}
213
214
215static SIM_RC
216hw_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 {
d946c288 261 hw_tree_parse (STATE_HW (sd)->tree, "%s", arg);
c906108c
SS
262 return SIM_RC_OK;
263 }
264
0802cc40
AC
265 case OPTION_HW_LIST:
266 {
267 sim_hw_print (sd, sim_io_vprintf);
268 return SIM_RC_OK;
269 }
028f6515 270
c906108c
SS
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
291static MODULE_INIT_FN sim_hw_init;
292static MODULE_UNINSTALL_FN sim_hw_uninstall;
293
2849d28d
MF
294/* Provide a prototype to silence -Wmissing-prototypes. */
295SIM_RC sim_install_hw (struct sim_state *sd);
296
297/* Establish this object. */
c906108c 298SIM_RC
2849d28d 299sim_install_hw (struct sim_state *sd)
c906108c
SS
300{
301 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
302 sim_add_option_table (sd, NULL, hw_options);
303 sim_module_add_uninstall_fn (sd, sim_hw_uninstall);
304 sim_module_add_init_fn (sd, sim_hw_init);
305 STATE_HW (sd) = ZALLOC (struct sim_hw);
306 STATE_HW (sd)->tree = hw_tree_create (sd, "core");
307 return SIM_RC_OK;
308}
309
310
311static SIM_RC
312sim_hw_init (struct sim_state *sd)
313{
314 /* FIXME: anything needed? */
315 hw_tree_finish (STATE_HW (sd)->tree);
316 if (STATE_HW (sd)->info_p)
317 sim_hw_print (sd, sim_io_vprintf);
318 return SIM_RC_OK;
319}
320
321/* Uninstall the "hw" subsystem from the simulator. */
322
323static void
324sim_hw_uninstall (struct sim_state *sd)
325{
9bd90cce 326 hw_tree_delete (STATE_HW (sd)->tree);
d79fe0d6 327 free (STATE_HW (sd));
c906108c
SS
328 STATE_HW (sd) = NULL;
329}
330
331
332\f
333/* Data transfers to/from the hardware device tree. There are several
334 cases. */
335
336
337/* CPU: The simulation is running and the current CPU/CIA
338 initiates a data transfer. */
339
028f6515 340void
c906108c
SS
341sim_cpu_hw_io_read_buffer (sim_cpu *cpu,
342 sim_cia cia,
343 struct hw *hw,
344 void *dest,
345 int space,
346 unsigned_word addr,
347 unsigned nr_bytes)
348{
349 SIM_DESC sd = CPU_STATE (cpu);
350 STATE_HW (sd)->cpu = cpu;
351 STATE_HW (sd)->cia = cia;
352 if (hw_io_read_buffer (hw, dest, space, addr, nr_bytes) != nr_bytes)
353 sim_engine_abort (sd, cpu, cia, "broken CPU read");
354}
355
028f6515 356void
c906108c
SS
357sim_cpu_hw_io_write_buffer (sim_cpu *cpu,
358 sim_cia cia,
359 struct hw *hw,
360 const void *source,
361 int space,
362 unsigned_word addr,
363 unsigned nr_bytes)
364{
365 SIM_DESC sd = CPU_STATE (cpu);
366 STATE_HW (sd)->cpu = cpu;
367 STATE_HW (sd)->cia = cia;
368 if (hw_io_write_buffer (hw, source, space, addr, nr_bytes) != nr_bytes)
369 sim_engine_abort (sd, cpu, cia, "broken CPU write");
370}
371
372
373
374
375/* SYSTEM: A data transfer is being initiated by the system. */
376
028f6515 377unsigned
c906108c
SS
378sim_hw_io_read_buffer (struct sim_state *sd,
379 struct hw *hw,
380 void *dest,
381 int space,
382 unsigned_word addr,
383 unsigned nr_bytes)
384{
385 STATE_HW (sd)->cpu = NULL;
386 return hw_io_read_buffer (hw, dest, space, addr, nr_bytes);
387}
388
389unsigned
390sim_hw_io_write_buffer (struct sim_state *sd,
391 struct hw *hw,
392 const void *source,
393 int space,
394 unsigned_word addr,
395 unsigned nr_bytes)
396{
397 STATE_HW (sd)->cpu = NULL;
398 return hw_io_write_buffer (hw, source, space, addr, nr_bytes);
399}
400
401
402\f
403/* Abort the simulation specifying HW as the reason */
404
405void
406hw_vabort (struct hw *me,
407 const char *fmt,
408 va_list ap)
409{
410 const char *name;
411 char *msg;
412 /* find an identity */
413 if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0')
414 name = hw_path (me);
415 else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0')
416 name = hw_name (me);
417 else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0')
418 name = hw_family (me);
419 else
420 name = "device";
421 /* construct an updated format string */
422 msg = alloca (strlen (name) + strlen (": ") + strlen (fmt) + 1);
423 strcpy (msg, name);
424 strcat (msg, ": ");
425 strcat (msg, fmt);
426 /* report the problem */
427 sim_engine_vabort (hw_system (me),
428 STATE_HW (hw_system (me))->cpu,
429 STATE_HW (hw_system (me))->cia,
430 msg, ap);
431}
432
433void
434hw_abort (struct hw *me,
435 const char *fmt,
436 ...)
437{
438 va_list ap;
439 /* report the problem */
440 va_start (ap, fmt);
441 hw_vabort (me, fmt, ap);
442 va_end (ap);
443}
444
445void
446sim_hw_abort (struct sim_state *sd,
447 struct hw *me,
448 const char *fmt,
449 ...)
450{
451 va_list ap;
452 va_start (ap, fmt);
453 if (me == NULL)
454 sim_engine_vabort (sd, NULL, NULL_CIA, fmt, ap);
455 else
456 hw_vabort (me, fmt, ap);
457 va_end (ap);
458}
459
460
461/* MISC routines to tie HW into the rest of the system */
462
463void
464hw_halt (struct hw *me,
465 int reason,
466 int status)
467{
468 struct sim_state *sd = hw_system (me);
469 struct sim_hw *sim = STATE_HW (sd);
470 sim_engine_halt (sd, sim->cpu, NULL, sim->cia, reason, status);
471}
472
473struct _sim_cpu *
474hw_system_cpu (struct hw *me)
475{
476 return STATE_HW (hw_system (me))->cpu;
477}
478
479void
480hw_trace (struct hw *me,
481 const char *fmt,
482 ...)
483{
484 if (hw_trace_p (me)) /* to be sure, to be sure */
485 {
486 va_list ap;
487 va_start (ap, fmt);
488 sim_io_eprintf (hw_system (me), "%s: ", hw_path (me));
489 sim_io_evprintf (hw_system (me), fmt, ap);
490 sim_io_eprintf (hw_system (me), "\n");
491 va_end (ap);
492 }
493}
494
495
496/* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */
497
498int
499do_hw_poll_read (struct hw *me,
500 do_hw_poll_read_method *read,
501 int sim_io_fd,
502 void *buf,
503 unsigned sizeof_buf)
504{
505 int status = read (hw_system (me), sim_io_fd, buf, sizeof_buf);
506 if (status > 0)
507 return status;
508 else if (status == 0 && sizeof_buf == 0)
509 return 0;
510 else if (status == 0)
511 return HW_IO_EOF;
512 else /* status < 0 */
513 {
514#ifdef EAGAIN
515 if (STATE_CALLBACK (hw_system (me))->last_errno == EAGAIN)
516 return HW_IO_NOT_READY;
517 else
518 return HW_IO_EOF;
519#else
520 return HW_IO_EOF;
521#endif
522 }
523}