1 /* Simulator hardware option handling.
2 Copyright (C) 1998-2023 Free Software Foundation, Inc.
3 Contributed by Cygnus Support and Andrew Cagney.
5 This file is part of GDB, the GNU debugger.
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.
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.
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/>. */
20 /* This must come before any other includes. */
30 #include "sim-assert.h"
31 #include "sim-options.h"
32 #include "sim/callback.h"
37 #include "hw-device.h"
45 /* if called from a processor */
52 sim_hw_parse (struct sim_state
*sd
,
59 current
= hw_tree_vparse (STATE_HW (sd
)->tree
, fmt
, ap
);
65 struct sim_state
*file
;
66 void (*print
) (struct sim_state
*, const char *, va_list ap
);
70 do_print (void *file
, const char *fmt
, ...)
72 struct printer
*p
= file
;
75 p
->print (p
->file
, fmt
, ap
);
80 sim_hw_print (struct sim_state
*sd
,
81 void (*print
) (struct sim_state
*, const char *, va_list ap
))
86 hw_tree_print (STATE_HW (sd
)->tree
, do_print
, &p
);
92 /* command line options. */
95 OPTION_HW_INFO
= OPTION_START
,
102 static DECLARE_OPTION_HANDLER (hw_option_handler
);
104 static const OPTION hw_options
[] =
106 { {"hw-info", no_argument
, NULL
, OPTION_HW_INFO
},
107 '\0', NULL
, "List configurable hw regions",
108 hw_option_handler
, NULL
},
109 { {"info-hw", no_argument
, NULL
, OPTION_HW_INFO
},
111 hw_option_handler
, NULL
},
113 { {"hw-trace", optional_argument
, NULL
, OPTION_HW_TRACE
},
114 '\0', "on|off", "Trace all hardware devices",
115 hw_option_handler
, NULL
},
116 { {"trace-hw", optional_argument
, NULL
, OPTION_HW_TRACE
},
118 hw_option_handler
, NULL
},
120 { {"hw-device", required_argument
, NULL
, OPTION_HW_DEVICE
},
121 '\0', "DEVICE", "Add the specified device",
122 hw_option_handler
, NULL
},
124 { {"hw-list", no_argument
, NULL
, OPTION_HW_LIST
},
125 '\0', NULL
, "List the device tree",
126 hw_option_handler
, NULL
},
128 { {"hw-file", required_argument
, NULL
, OPTION_HW_FILE
},
129 '\0', "FILE", "Add the devices listed in the file",
130 hw_option_handler
, NULL
},
132 { {NULL
, no_argument
, NULL
, 0}, '\0', NULL
, NULL
, NULL
, NULL
}
137 /* Copied from ../ppc/psim.c:psim_merge_device_file() */
140 merge_device_file (struct sim_state
*sd
,
141 const char *file_name
)
144 struct hw
*current
= STATE_HW (sd
)->tree
;
145 char *device_path
= NULL
;
147 ssize_t device_path_len
;
149 /* try opening the file */
150 description
= fopen (file_name
, "r");
151 if (description
== NULL
)
157 while ((device_path_len
= getline (&device_path
, &buf_size
, description
)) > 0)
160 char *next_line
= NULL
;
162 if (device_path
[device_path_len
- 1] == '\n')
163 device_path
[--device_path_len
] = '\0';
165 /* skip comments ("#" or ";") and blank lines lines */
166 for (device
= device_path
;
167 *device
!= '\0' && isspace (*device
);
171 || device
[0] == '\0')
174 /* merge any appended lines */
175 while (device_path
[device_path_len
- 1] == '\\')
177 size_t next_buf_size
= 0;
178 ssize_t next_line_len
;
180 /* zap the `\' at the end of the line */
181 device_path
[--device_path_len
] = '\0';
183 /* get the next line */
184 next_line_len
= getline (&next_line
, &next_buf_size
, description
);
185 if (next_line_len
<= 0)
188 if (next_line
[next_line_len
- 1] == '\n')
189 next_line
[--next_line_len
] = '\0';
191 /* append the next line */
192 if (buf_size
- device_path_len
<= next_line_len
)
194 ptrdiff_t offset
= device
- device_path
;
196 buf_size
+= next_buf_size
;
197 device_path
= xrealloc (device_path
, buf_size
);
198 device
= device_path
+ offset
;
200 memcpy (device_path
+ device_path_len
, next_line
,
202 device_path_len
+= next_line_len
;
206 /* parse this line */
207 current
= hw_tree_parse (current
, "%s", device
);
211 fclose (description
);
217 hw_option_handler (struct sim_state
*sd
, sim_cpu
*cpu
, int opt
,
218 char *arg
, int is_command
)
225 /* delay info until after the tree is finished */
226 STATE_HW (sd
)->info_p
= 1;
231 case OPTION_HW_TRACE
:
235 STATE_HW (sd
)->trace_p
= 1;
237 else if (strcmp (arg
, "yes") == 0
238 || strcmp (arg
, "on") == 0)
240 STATE_HW (sd
)->trace_p
= 1;
242 else if (strcmp (arg
, "no") == 0
243 || strcmp (arg
, "off") == 0)
245 STATE_HW (sd
)->trace_p
= 0;
249 sim_io_eprintf (sd
, "Option --hw-trace ignored\n");
250 /* set tracing on all devices */
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");
260 case OPTION_HW_DEVICE
:
262 hw_tree_parse (STATE_HW (sd
)->tree
, "%s", arg
);
268 sim_hw_print (sd
, sim_io_vprintf
);
274 return merge_device_file (sd
, arg
);
278 sim_io_eprintf (sd
, "Unknown hw option %d\n", opt
);
287 /* "hw" module install handler.
289 This is called via sim_module_install to install the "hw" subsystem
290 into the simulator. */
292 static MODULE_INIT_FN sim_hw_init
;
293 static MODULE_UNINSTALL_FN sim_hw_uninstall
;
295 /* Provide a prototype to silence -Wmissing-prototypes. */
296 SIM_RC
sim_install_hw (struct sim_state
*sd
);
298 /* Establish this object. */
300 sim_install_hw (struct sim_state
*sd
)
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");
313 sim_hw_init (struct sim_state
*sd
)
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
);
322 /* Uninstall the "hw" subsystem from the simulator. */
325 sim_hw_uninstall (struct sim_state
*sd
)
327 hw_tree_delete (STATE_HW (sd
)->tree
);
328 free (STATE_HW (sd
));
329 STATE_HW (sd
) = NULL
;
334 /* Data transfers to/from the hardware device tree. There are several
338 /* CPU: The simulation is running and the current CPU/CIA
339 initiates a data transfer. */
342 sim_cpu_hw_io_read_buffer (sim_cpu
*cpu
,
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");
358 sim_cpu_hw_io_write_buffer (sim_cpu
*cpu
,
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");
376 /* SYSTEM: A data transfer is being initiated by the system. */
379 sim_hw_io_read_buffer (struct sim_state
*sd
,
386 STATE_HW (sd
)->cpu
= NULL
;
387 return hw_io_read_buffer (hw
, dest
, space
, addr
, nr_bytes
);
391 sim_hw_io_write_buffer (struct sim_state
*sd
,
398 STATE_HW (sd
)->cpu
= NULL
;
399 return hw_io_write_buffer (hw
, source
, space
, addr
, nr_bytes
);
404 /* Abort the simulation specifying HW as the reason */
407 hw_vabort (struct hw
*me
,
416 /* find an identity */
417 if (me
!= NULL
&& hw_path (me
) != NULL
&& hw_path (me
) [0] != '\0')
419 else if (me
!= NULL
&& hw_name (me
) != NULL
&& hw_name (me
)[0] != '\0')
421 else if (me
!= NULL
&& hw_family (me
) != NULL
&& hw_family (me
)[0] != '\0')
422 name
= hw_family (me
);
426 /* Expand FMT and AP into MSG buffer. */
428 len
= vsnprintf (NULL
, 0, fmt
, cpy
) + 1;
431 vsnprintf (msg
, len
, fmt
, ap
);
433 /* report the problem */
434 sim_engine_abort (hw_system (me
),
435 STATE_HW (hw_system (me
))->cpu
,
436 STATE_HW (hw_system (me
))->cia
,
437 "%s: %s", name
, msg
);
441 hw_abort (struct hw
*me
,
446 /* report the problem */
448 hw_vabort (me
, fmt
, ap
);
453 sim_hw_abort (struct sim_state
*sd
,
461 sim_engine_vabort (sd
, NULL
, NULL_CIA
, fmt
, ap
);
463 hw_vabort (me
, fmt
, ap
);
468 /* MISC routines to tie HW into the rest of the system */
471 hw_halt (struct hw
*me
,
475 struct sim_state
*sd
= hw_system (me
);
476 struct sim_hw
*sim
= STATE_HW (sd
);
477 sim_engine_halt (sd
, sim
->cpu
, NULL
, sim
->cia
, reason
, status
);
481 hw_system_cpu (struct hw
*me
)
483 return STATE_HW (hw_system (me
))->cpu
;
487 hw_trace (struct hw
*me
,
491 if (hw_trace_p (me
)) /* to be sure, to be sure */
495 sim_io_eprintf (hw_system (me
), "%s: ", hw_path (me
));
496 sim_io_evprintf (hw_system (me
), fmt
, ap
);
497 sim_io_eprintf (hw_system (me
), "\n");
503 /* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */
506 do_hw_poll_read (struct hw
*me
,
507 do_hw_poll_read_method
*read
,
512 int status
= read (hw_system (me
), sim_io_fd
, buf
, sizeof_buf
);
515 else if (status
== 0 && sizeof_buf
== 0)
517 else if (status
== 0)
519 else /* status < 0 */
522 if (STATE_CALLBACK (hw_system (me
))->last_errno
== EAGAIN
)
523 return HW_IO_NOT_READY
;