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