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