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