* sim-hw.c: Include ctype.h.
authorAndrew Cagney <cagney@redhat.com>
Thu, 21 May 1998 08:17:31 +0000 (08:17 +0000)
committerAndrew Cagney <cagney@redhat.com>
Thu, 21 May 1998 08:17:31 +0000 (08:17 +0000)
(do_hw_poll_read): Do not assume EAGAIN.

sim/common/ChangeLog
sim/common/sim-hw.c [new file with mode: 0644]
sim/common/sim-module.c

index e8d3fec9dbe34fb714aaf6f25072a9d7499dabdd..3b1de8dfe6a12f22f61ab14b5c142a072e5f5ef9 100644 (file)
@@ -1,3 +1,10 @@
+start-sanitize-am30
+Thu May 21 17:57:16 1998  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * sim-hw.c: Include ctype.h.
+       (do_hw_poll_read): Do not assume EAGAIN.
+
+end-sanitize-am30
 Wed May 20 04:37:57 1998  Doug Evans  <devans@seba.cygnus.com>
 
        * cgen-trace.c (first_insn_p): New static local.
diff --git a/sim/common/sim-hw.c b/sim/common/sim-hw.c
new file mode 100644 (file)
index 0000000..51b7b0f
--- /dev/null
@@ -0,0 +1,564 @@
+/* Simulator hardware option handling.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   Contributed by Cygnus Support and Andrew Cagney.
+
+This file is part of GDB, the GNU debugger.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sim-main.h"
+#include "sim-assert.h"
+#include "sim-options.h"
+
+#include "sim-hw.h"
+
+#include "hw-tree.h"
+#include "hw-device.h"
+#include "hw-base.h"
+
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <ctype.h>
+#include <sys/errno.h>
+
+
+struct sim_hw {
+  struct hw *tree;
+  int trace_p;
+  int info_p;
+  /* if called from a processor */
+  sim_cpu *cpu;
+  sim_cia cia;
+};
+
+
+void
+sim_hw_parse (struct sim_state *sd,
+             const char *fmt,
+             ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  hw_tree_vparse (STATE_HW (sd)->tree, fmt, ap);
+  va_end (ap);
+}
+
+struct printer {
+  struct sim_state *file;
+  void (*print) (struct sim_state *, const char *, va_list ap);
+};
+
+static void
+do_print (void *file, const char *fmt, ...)
+{
+  struct printer *p = file;
+  va_list ap;
+  va_start (ap, fmt);
+  p->print (p->file, fmt, ap);
+  va_end (ap);
+}
+
+void
+sim_hw_print (struct sim_state *sd,
+             void (*print) (struct sim_state *, const char *, va_list ap))
+{
+  struct printer p;
+  p.file = sd;
+  p.print = print;
+  hw_tree_print (STATE_HW (sd)->tree, do_print, &p);
+}
+
+
+
+
+/* command line options. */
+
+enum {
+  OPTION_HW_INFO = OPTION_START,
+  OPTION_HW_TRACE,
+  OPTION_HW_DEVICE,
+  OPTION_HW_FILE,
+};
+
+static DECLARE_OPTION_HANDLER (hw_option_handler);
+
+static const OPTION hw_options[] =
+{
+  { {"hw-info", no_argument, NULL, OPTION_HW_INFO },
+      '\0', NULL, "List configurable hw regions",
+      hw_option_handler },
+  { {"info-hw", no_argument, NULL, OPTION_HW_INFO },
+      '\0', NULL, NULL,
+      hw_option_handler },
+
+  { {"hw-trace", optional_argument, NULL, OPTION_HW_TRACE },
+      '\0', "on|off", "Trace all hardware devices",
+      hw_option_handler },
+  { {"trace-hw", optional_argument, NULL, OPTION_HW_TRACE },
+      '\0', NULL, NULL,
+      hw_option_handler },
+
+  { {"hw-device", required_argument, NULL, OPTION_HW_DEVICE },
+      '\0', "DEVICE", "Add the specified device",
+      hw_option_handler },
+
+  { {"hw-file", required_argument, NULL, OPTION_HW_FILE },
+      '\0', "FILE", "Add the devices listed in the file",
+      hw_option_handler },
+
+  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
+};
+
+
+
+/* Copied from ../ppc/psim.c:psim_merge_device_file() */
+
+static SIM_RC
+merge_device_file (struct sim_state *sd,
+                  const char *file_name)
+{
+  FILE *description;
+  struct hw *current = STATE_HW (sd)->tree;
+  int line_nr;
+  char device_path[1000];
+  
+  /* try opening the file */
+  description = fopen (file_name, "r");
+  if (description == NULL)
+    {
+      perror (file_name);
+      return SIM_RC_FAIL;
+    }
+  
+  line_nr = 0;
+  while (fgets (device_path, sizeof(device_path), description))
+    {
+      char *device;
+      /* check that a complete line was read */
+      if (strchr (device_path, '\n') == NULL)
+       {
+         fclose (description);
+         sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr);
+         return SIM_RC_FAIL;
+       }
+      *strchr (device_path, '\n') = '\0';
+      line_nr++;
+      /* skip comments ("#" or ";") and blank lines lines */
+      for (device = device_path;
+          *device != '\0' && isspace (*device);
+          device++);
+      if (device[0] == '#'
+         || device[0] == ';'
+         || device[0] == '\0')
+       continue;
+      /* merge any appended lines */
+      while (device_path[strlen (device_path) - 1] == '\\')
+       {
+         int curlen = strlen (device_path) - 1;
+         /* zap the `\' at the end of the line */
+         device_path[curlen] = '\0';
+         /* append the next line */
+         if (!fgets (device_path + curlen,
+                     sizeof (device_path) - curlen,
+                     description))
+           {
+             fclose (description);
+             sim_io_eprintf (sd, "%s:%d: unexpected eof", file_name, line_nr);
+             return SIM_RC_FAIL;
+           }
+         if (strchr(device_path, '\n') == NULL)
+           {
+             fclose(description);
+             sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr);
+             return SIM_RC_FAIL;
+           }
+         *strchr(device_path, '\n') = '\0';
+         line_nr++;
+       }
+      /* parse this line */
+      current = hw_tree_parse (current, "%s", device);
+    }
+  fclose (description);
+  return SIM_RC_OK;
+}
+
+
+static SIM_RC
+hw_option_handler (struct sim_state *sd, sim_cpu *cpu, int opt,
+                  char *arg, int is_command)
+{
+  switch (opt)
+    {
+
+    case OPTION_HW_INFO:
+      {
+       /* delay info until after the tree is finished */
+       STATE_HW (sd)->info_p = 1;
+       return SIM_RC_OK;
+       break;
+      }
+
+    case OPTION_HW_TRACE:
+      {
+       if (arg == NULL)
+         {
+           STATE_HW (sd)->trace_p = 1;
+         }
+       else if (strcmp (arg, "yes") == 0
+                || strcmp (arg, "on") == 0)
+         {
+           STATE_HW (sd)->trace_p = 1;
+         }
+       else if (strcmp (arg, "no") == 0
+                || strcmp (arg, "off") == 0)
+         {
+           STATE_HW (sd)->trace_p = 0;
+         }
+       else
+         {
+           sim_io_eprintf (sd, "Option --hw-trace ignored\n");
+           /* set tracing on all devices */
+           return SIM_RC_FAIL;
+         }
+       /* FIXME: Not very nice - see also hw-base.c */
+       if (STATE_HW (sd)->trace_p)
+         hw_tree_parse (STATE_HW (sd)->tree, "/global-trace? true");
+       return SIM_RC_OK;
+       break;
+      }
+
+    case OPTION_HW_DEVICE:
+      {
+       hw_tree_parse (STATE_HW (sd)->tree, arg);
+       return SIM_RC_OK;
+      }
+
+    case OPTION_HW_FILE:
+      {
+       return merge_device_file (sd, arg);
+      }
+
+    default:
+      sim_io_eprintf (sd, "Unknown hw option %d\n", opt);
+      return SIM_RC_FAIL;
+
+    }
+
+  return SIM_RC_FAIL;
+}
+
+
+/* "hw" module install handler.
+
+   This is called via sim_module_install to install the "hw" subsystem
+   into the simulator.  */
+
+static MODULE_INIT_FN sim_hw_init;
+static MODULE_UNINSTALL_FN sim_hw_uninstall;
+
+SIM_RC
+sim_hw_install (struct sim_state *sd)
+{
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+  sim_add_option_table (sd, NULL, hw_options);
+  sim_module_add_uninstall_fn (sd, sim_hw_uninstall);
+  sim_module_add_init_fn (sd, sim_hw_init);
+  STATE_HW (sd) = ZALLOC (struct sim_hw);
+  STATE_HW (sd)->tree = hw_tree_create (sd, "core");
+  return SIM_RC_OK;
+}
+
+
+static SIM_RC
+sim_hw_init (struct sim_state *sd)
+{
+  /* FIXME: anything needed? */
+  hw_tree_finish (STATE_HW (sd)->tree);
+  if (STATE_HW (sd)->info_p)
+    sim_hw_print (sd, sim_io_vprintf);
+  return SIM_RC_OK;
+}
+
+/* Uninstall the "hw" subsystem from the simulator.  */
+
+static void
+sim_hw_uninstall (struct sim_state *sd)
+{
+  /* hw_tree_delete (STATE_HW (sd)->tree); */
+  zfree (STATE_HW (sd));
+  STATE_HW (sd) = NULL;
+}
+
+
+\f
+/* Data transfers to/from the hardware device tree.  There are several
+   cases. */
+
+
+/* CPU: The simulation is running and the current CPU/CIA
+   initiates a data transfer. */
+
+void 
+sim_cpu_hw_io_read_buffer (sim_cpu *cpu,
+                          sim_cia cia,
+                          struct hw *hw,
+                          void *dest,
+                          int space,
+                          unsigned_word addr,
+                          unsigned nr_bytes)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  STATE_HW (sd)->cpu = cpu;
+  STATE_HW (sd)->cia = cia;
+  if (hw_io_read_buffer (hw, dest, space, addr, nr_bytes) != nr_bytes)
+    sim_engine_abort (sd, cpu, cia, "broken CPU read");
+}
+
+void 
+sim_cpu_hw_io_write_buffer (sim_cpu *cpu,
+                           sim_cia cia,
+                           struct hw *hw,
+                           const void *source,
+                           int space,
+                           unsigned_word addr,
+                           unsigned nr_bytes)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  STATE_HW (sd)->cpu = cpu;
+  STATE_HW (sd)->cia = cia;
+  if (hw_io_write_buffer (hw, source, space, addr, nr_bytes) != nr_bytes)
+    sim_engine_abort (sd, cpu, cia, "broken CPU write");
+}
+
+
+
+
+/* SYSTEM: A data transfer is being initiated by the system. */
+
+unsigned 
+sim_hw_io_read_buffer (struct sim_state *sd,
+                      struct hw *hw,
+                      void *dest,
+                      int space,
+                      unsigned_word addr,
+                      unsigned nr_bytes)
+{
+  STATE_HW (sd)->cpu = NULL;
+  return hw_io_read_buffer (hw, dest, space, addr, nr_bytes);
+}
+
+unsigned
+sim_hw_io_write_buffer (struct sim_state *sd,
+                       struct hw *hw,
+                       const void *source,
+                       int space,
+                       unsigned_word addr,
+                       unsigned nr_bytes)
+{
+  STATE_HW (sd)->cpu = NULL;
+  return hw_io_write_buffer (hw, source, space, addr, nr_bytes);
+}
+
+
+\f
+/* Abort the simulation specifying HW as the reason */
+
+void
+hw_vabort (struct hw *me,
+          const char *fmt,
+          va_list ap)
+{
+  const char *name;
+  char *msg;
+  /* find an identity */
+  if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0')
+    name = hw_path (me);
+  else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0')
+    name = hw_name (me);
+  else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0')
+    name = hw_family (me);
+  else
+    name = "device";
+  /* construct an updated format string */
+  msg = alloca (strlen (name) + strlen (": ") + strlen (fmt) + 1);
+  strcpy (msg, name);
+  strcat (msg, ": ");
+  strcat (msg, fmt);
+  /* report the problem */
+  sim_engine_vabort (hw_system (me),
+                    STATE_HW (hw_system (me))->cpu,
+                    STATE_HW (hw_system (me))->cia,
+                    msg, ap);
+}
+
+void
+hw_abort (struct hw *me,
+         const char *fmt,
+         ...)
+{
+  va_list ap;
+  /* report the problem */
+  va_start (ap, fmt);
+  hw_vabort (me, fmt, ap);
+  va_end (ap);
+}
+
+void
+sim_hw_abort (struct sim_state *sd,
+             struct hw *me,
+             const char *fmt,
+             ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  if (me == NULL)
+    sim_engine_vabort (sd, NULL, NULL_CIA, fmt, ap);
+  else
+    hw_vabort (me, fmt, ap);
+  va_end (ap);
+}
+
+
+/* MISC routines to tie HW into the rest of the system */
+
+void
+hw_halt (struct hw *me,
+        int reason,
+        int status)
+{
+  struct sim_state *sd = hw_system (me);
+  struct sim_hw *sim = STATE_HW (sd);
+  sim_engine_halt (sd, sim->cpu, NULL, sim->cia, reason, status);
+}
+
+struct _sim_cpu *
+hw_system_cpu (struct hw *me)
+{
+  return STATE_HW (hw_system (me))->cpu;
+}
+
+void
+hw_trace (struct hw *me,
+         const char *fmt,
+         ...)
+{
+  if (hw_trace_p (me)) /* to be sure, to be sure */
+    {
+      va_list ap;
+      va_start (ap, fmt);
+      sim_io_eprintf (hw_system (me), "%s: ", hw_path (me));
+      sim_io_evprintf (hw_system (me), fmt, ap);
+      sim_io_eprintf (hw_system (me), "\n");
+      va_end (ap);
+    }
+}
+
+
+/* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */
+
+int
+do_hw_poll_read (struct hw *me,
+                do_hw_poll_read_method *read,
+                int sim_io_fd,
+                void *buf,
+                unsigned sizeof_buf)
+{
+  int status = read (hw_system (me), sim_io_fd, buf, sizeof_buf);
+  if (status > 0)
+    return status;
+  else if (status == 0 && sizeof_buf == 0)
+    return 0;
+  else if (status == 0)
+    return HW_IO_EOF;
+  else /* status < 0 */
+    {
+#ifdef EAGAIN
+      if (STATE_CALLBACK (hw_system (me))->last_errno == EAGAIN)
+       return HW_IO_NOT_READY;
+      else
+       return HW_IO_EOF;
+#else
+      return HW_IO_EOF;
+#endif
+    }
+}
+
+\f
+/* The event queue abstraction (for devices) */
+
+
+struct _hw_event {
+  void *data;
+  struct hw *me;
+  hw_event_handler *handler;
+  sim_event *real;
+};
+
+/* Pass the H/W event onto the real handler */
+
+static void
+bounce_hw_event (SIM_DESC sd,
+                void *data)
+{
+  hw_event event = * (hw_event*) data;
+  zfree (data);
+  /* if we are delivering an event, we don't have a CPU. */
+  STATE_HW (sd)->cpu = NULL;
+  event.handler (event.me, event.data);
+}
+
+
+/* Map onto the event functions */
+
+hw_event *
+hw_event_queue_schedule (struct hw *me,
+                        signed64 delta_time,
+                        hw_event_handler *handler,
+                        void *data)
+{
+  hw_event *event = ZALLOC (hw_event);
+  event->data = data;
+  event->handler = handler;
+  event->me = me;
+  event->real = sim_events_schedule (hw_system (me),
+                                    delta_time,
+                                    bounce_hw_event,
+                                    event);
+  return event;
+}
+
+void
+hw_event_queue_deschedule (struct hw *me,
+                          hw_event *event_to_remove)
+{
+  sim_events_deschedule (hw_system (me),
+                        event_to_remove->real);
+  zfree (event_to_remove);
+}
+
+signed64
+hw_event_queue_time (struct hw *me)
+{
+  return sim_events_time (hw_system (me));
+}
index 0fb54717c54840d7a35d9bcb277ffef1cd2d5ff3..970e7258233c73eb536dec86ba06c9681ccf4c36 100644 (file)
@@ -23,6 +23,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "sim-options.h"
 #include "sim-assert.h"
 
+/* start-sanitize-am30 */
+#if WITH_HW
+#include "sim-hw.h"
+#endif
+/* end-sanitize-am30 */
+
 #include "libiberty.h"
 
 /* List of all modules.  */
@@ -50,11 +56,16 @@ static MODULE_INSTALL_FN * const modules[] = {
   scache_install,
 #endif
 #ifdef SIM_HAVE_MODEL
-  model_install,
+  sim_model_install,
 #endif
 #ifdef SIM_HAVE_BREAKPOINTS
   sim_break_install,
 #endif
+  /* start-sanitize-am30 */
+#if WITH_HW
+  sim_hw_install,
+#endif
+  /* end-sanitize-am30 */
   /* Configured in [simulator specific] additional modules.  */
 #ifdef MODULE_LIST
   MODULE_LIST