1 /* Simulator hardware option handling.
2 Copyright (C) 1998-2021 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/>. */
21 #include "sim-assert.h"
22 #include "sim-options.h"
27 #include "hw-device.h"
41 /* if called from a processor */
48 sim_hw_parse (struct sim_state
*sd
,
55 current
= hw_tree_vparse (STATE_HW (sd
)->tree
, fmt
, ap
);
61 struct sim_state
*file
;
62 void (*print
) (struct sim_state
*, const char *, va_list ap
);
66 do_print (void *file
, const char *fmt
, ...)
68 struct printer
*p
= file
;
71 p
->print (p
->file
, fmt
, ap
);
76 sim_hw_print (struct sim_state
*sd
,
77 void (*print
) (struct sim_state
*, const char *, va_list ap
))
82 hw_tree_print (STATE_HW (sd
)->tree
, do_print
, &p
);
88 /* command line options. */
91 OPTION_HW_INFO
= OPTION_START
,
98 static DECLARE_OPTION_HANDLER (hw_option_handler
);
100 static const OPTION hw_options
[] =
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
},
107 hw_option_handler
, NULL
},
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
},
114 hw_option_handler
, NULL
},
116 { {"hw-device", required_argument
, NULL
, OPTION_HW_DEVICE
},
117 '\0', "DEVICE", "Add the specified device",
118 hw_option_handler
, NULL
},
120 { {"hw-list", no_argument
, NULL
, OPTION_HW_LIST
},
121 '\0', NULL
, "List the device tree",
122 hw_option_handler
, NULL
},
124 { {"hw-file", required_argument
, NULL
, OPTION_HW_FILE
},
125 '\0', "FILE", "Add the devices listed in the file",
126 hw_option_handler
, NULL
},
128 { {NULL
, no_argument
, NULL
, 0}, '\0', NULL
, NULL
, NULL
, NULL
}
133 /* Copied from ../ppc/psim.c:psim_merge_device_file() */
136 merge_device_file (struct sim_state
*sd
,
137 const char *file_name
)
140 struct hw
*current
= STATE_HW (sd
)->tree
;
141 char *device_path
= NULL
;
143 ssize_t device_path_len
;
145 /* try opening the file */
146 description
= fopen (file_name
, "r");
147 if (description
== NULL
)
153 while ((device_path_len
= getline (&device_path
, &buf_size
, description
)) > 0)
156 char *next_line
= NULL
;
158 if (device_path
[device_path_len
- 1] == '\n')
159 device_path
[--device_path_len
] = '\0';
161 /* skip comments ("#" or ";") and blank lines lines */
162 for (device
= device_path
;
163 *device
!= '\0' && isspace (*device
);
167 || device
[0] == '\0')
170 /* merge any appended lines */
171 while (device_path
[device_path_len
- 1] == '\\')
173 size_t next_buf_size
= 0;
174 ssize_t next_line_len
;
176 /* zap the `\' at the end of the line */
177 device_path
[--device_path_len
] = '\0';
179 /* get the next line */
180 next_line_len
= getline (&next_line
, &next_buf_size
, description
);
181 if (next_line_len
<= 0)
184 if (next_line
[next_line_len
- 1] == '\n')
185 next_line
[--next_line_len
] = '\0';
187 /* append the next line */
188 if (buf_size
- device_path_len
<= next_line_len
)
190 ptrdiff_t offset
= device
- device_path
;
192 buf_size
+= next_buf_size
;
193 device_path
= xrealloc (device_path
, buf_size
);
194 device
= device_path
+ offset
;
196 memcpy (device_path
+ device_path_len
, next_line
,
198 device_path_len
+= next_line_len
;
202 /* parse this line */
203 current
= hw_tree_parse (current
, "%s", device
);
207 fclose (description
);
213 hw_option_handler (struct sim_state
*sd
, sim_cpu
*cpu
, int opt
,
214 char *arg
, int is_command
)
221 /* delay info until after the tree is finished */
222 STATE_HW (sd
)->info_p
= 1;
227 case OPTION_HW_TRACE
:
231 STATE_HW (sd
)->trace_p
= 1;
233 else if (strcmp (arg
, "yes") == 0
234 || strcmp (arg
, "on") == 0)
236 STATE_HW (sd
)->trace_p
= 1;
238 else if (strcmp (arg
, "no") == 0
239 || strcmp (arg
, "off") == 0)
241 STATE_HW (sd
)->trace_p
= 0;
245 sim_io_eprintf (sd
, "Option --hw-trace ignored\n");
246 /* set tracing on all devices */
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");
256 case OPTION_HW_DEVICE
:
258 hw_tree_parse (STATE_HW (sd
)->tree
, "%s", arg
);
264 sim_hw_print (sd
, sim_io_vprintf
);
270 return merge_device_file (sd
, arg
);
274 sim_io_eprintf (sd
, "Unknown hw option %d\n", opt
);
283 /* "hw" module install handler.
285 This is called via sim_module_install to install the "hw" subsystem
286 into the simulator. */
288 static MODULE_INIT_FN sim_hw_init
;
289 static MODULE_UNINSTALL_FN sim_hw_uninstall
;
291 /* Provide a prototype to silence -Wmissing-prototypes. */
292 SIM_RC
sim_install_hw (struct sim_state
*sd
);
294 /* Establish this object. */
296 sim_install_hw (struct sim_state
*sd
)
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");
309 sim_hw_init (struct sim_state
*sd
)
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
);
318 /* Uninstall the "hw" subsystem from the simulator. */
321 sim_hw_uninstall (struct sim_state
*sd
)
323 hw_tree_delete (STATE_HW (sd
)->tree
);
324 free (STATE_HW (sd
));
325 STATE_HW (sd
) = NULL
;
330 /* Data transfers to/from the hardware device tree. There are several
334 /* CPU: The simulation is running and the current CPU/CIA
335 initiates a data transfer. */
338 sim_cpu_hw_io_read_buffer (sim_cpu
*cpu
,
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");
354 sim_cpu_hw_io_write_buffer (sim_cpu
*cpu
,
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");
372 /* SYSTEM: A data transfer is being initiated by the system. */
375 sim_hw_io_read_buffer (struct sim_state
*sd
,
382 STATE_HW (sd
)->cpu
= NULL
;
383 return hw_io_read_buffer (hw
, dest
, space
, addr
, nr_bytes
);
387 sim_hw_io_write_buffer (struct sim_state
*sd
,
394 STATE_HW (sd
)->cpu
= NULL
;
395 return hw_io_write_buffer (hw
, source
, space
, addr
, nr_bytes
);
400 /* Abort the simulation specifying HW as the reason */
403 hw_vabort (struct hw
*me
,
409 /* find an identity */
410 if (me
!= NULL
&& hw_path (me
) != NULL
&& hw_path (me
) [0] != '\0')
412 else if (me
!= NULL
&& hw_name (me
) != NULL
&& hw_name (me
)[0] != '\0')
414 else if (me
!= NULL
&& hw_family (me
) != NULL
&& hw_family (me
)[0] != '\0')
415 name
= hw_family (me
);
418 /* construct an updated format string */
419 msg
= alloca (strlen (name
) + strlen (": ") + strlen (fmt
) + 1);
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
,
431 hw_abort (struct hw
*me
,
436 /* report the problem */
438 hw_vabort (me
, fmt
, ap
);
443 sim_hw_abort (struct sim_state
*sd
,
451 sim_engine_vabort (sd
, NULL
, NULL_CIA
, fmt
, ap
);
453 hw_vabort (me
, fmt
, ap
);
458 /* MISC routines to tie HW into the rest of the system */
461 hw_halt (struct hw
*me
,
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
);
471 hw_system_cpu (struct hw
*me
)
473 return STATE_HW (hw_system (me
))->cpu
;
477 hw_trace (struct hw
*me
,
481 if (hw_trace_p (me
)) /* to be sure, to be sure */
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");
493 /* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */
496 do_hw_poll_read (struct hw
*me
,
497 do_hw_poll_read_method
*read
,
502 int status
= read (hw_system (me
), sim_io_fd
, buf
, sizeof_buf
);
505 else if (status
== 0 && sizeof_buf
== 0)
507 else if (status
== 0)
509 else /* status < 0 */
512 if (STATE_CALLBACK (hw_system (me
))->last_errno
== EAGAIN
)
513 return HW_IO_NOT_READY
;