* sim-hw.c: Include ctype.h.
[external/binutils.git] / sim / common / sim-hw.c
1 /* Simulator hardware option handling.
2    Copyright (C) 1998 Free Software Foundation, Inc.
3    Contributed by Cygnus Support and Andrew Cagney.
4
5 This file is part of GDB, the GNU debugger.
6
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 2, or (at your option)
10 any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 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
46 struct 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
56 void
57 sim_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
67 struct printer {
68   struct sim_state *file;
69   void (*print) (struct sim_state *, const char *, va_list ap);
70 };
71
72 static void
73 do_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
82 void
83 sim_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
97 enum {
98   OPTION_HW_INFO = OPTION_START,
99   OPTION_HW_TRACE,
100   OPTION_HW_DEVICE,
101   OPTION_HW_FILE,
102 };
103
104 static DECLARE_OPTION_HANDLER (hw_option_handler);
105
106 static 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
137 static SIM_RC
138 merge_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
207 static SIM_RC
208 hw_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
277 static MODULE_INIT_FN sim_hw_init;
278 static MODULE_UNINSTALL_FN sim_hw_uninstall;
279
280 SIM_RC
281 sim_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
293 static SIM_RC
294 sim_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
305 static void
306 sim_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
322 void 
323 sim_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
338 void 
339 sim_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
359 unsigned 
360 sim_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
371 unsigned
372 sim_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
387 void
388 hw_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
415 void
416 hw_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
427 void
428 sim_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
445 void
446 hw_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
455 struct _sim_cpu *
456 hw_system_cpu (struct hw *me)
457 {
458   return STATE_HW (hw_system (me))->cpu;
459 }
460
461 void
462 hw_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
480 int
481 do_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 }
506
507 \f
508 /* The event queue abstraction (for devices) */
509
510
511 struct _hw_event {
512   void *data;
513   struct hw *me;
514   hw_event_handler *handler;
515   sim_event *real;
516 };
517
518 /* Pass the H/W event onto the real handler */
519
520 static void
521 bounce_hw_event (SIM_DESC sd,
522                  void *data)
523 {
524   hw_event event = * (hw_event*) data;
525   zfree (data);
526   /* if we are delivering an event, we don't have a CPU. */
527   STATE_HW (sd)->cpu = NULL;
528   event.handler (event.me, event.data);
529 }
530
531
532 /* Map onto the event functions */
533
534 hw_event *
535 hw_event_queue_schedule (struct hw *me,
536                          signed64 delta_time,
537                          hw_event_handler *handler,
538                          void *data)
539 {
540   hw_event *event = ZALLOC (hw_event);
541   event->data = data;
542   event->handler = handler;
543   event->me = me;
544   event->real = sim_events_schedule (hw_system (me),
545                                      delta_time,
546                                      bounce_hw_event,
547                                      event);
548   return event;
549 }
550
551 void
552 hw_event_queue_deschedule (struct hw *me,
553                            hw_event *event_to_remove)
554 {
555   sim_events_deschedule (hw_system (me),
556                          event_to_remove->real);
557   zfree (event_to_remove);
558 }
559
560 signed64
561 hw_event_queue_time (struct hw *me)
562 {
563   return sim_events_time (hw_system (me));
564 }