Clean up create/delete of hw-ports
authorAndrew Cagney <cagney@redhat.com>
Mon, 25 May 1998 07:08:48 +0000 (07:08 +0000)
committerAndrew Cagney <cagney@redhat.com>
Mon, 25 May 1998 07:08:48 +0000 (07:08 +0000)
sim/common/ChangeLog
sim/common/hw-base.c
sim/common/hw-base.h
sim/common/hw-ports.c [new file with mode: 0644]
sim/common/hw-ports.h [new file with mode: 0644]

index 9f0aa26e306e4afc99f766420501483fe981be98..d8e1cea3a588f5d6027acbee3e7eeab8da713fee 100644 (file)
@@ -1,3 +1,16 @@
+Mon May 25 16:55:16 1998  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * hw-base.c (panic_hw_port_event, empty_hw_ports): Move from here.
+       * hw-ports.c: To here.
+       
+       * hw-base.h, hw-ports.c (create_hw_port_data,
+       delete_hw_port_data): New functions.
+       * hw-base.c (hw_delete, hw_create): Call same.
+       
+       * hw-base.h (set_hw_ports, set_hw_port_event): Move set functions
+       from here.
+       * hw-ports.h: To here.
+
 Mon May 25 16:42:48 1998  Andrew Cagney  <cagney@b1.cygnus.com>
 
        * hw-device.c (hw_ioctl), hw-device.h (hw_ioctl_callback): Drop
index 8a5a2990456f32bb2130fb0ec822a0bbf09dcd83..e8c09f064b7dfb858098e3341f56089c4cfc0b53 100644 (file)
 #include "hw-base.h"
 
 
-/* LATER: #include "hwconfig.h" */
-extern const struct hw_device_descriptor dv_core_descriptor[];
-extern const struct hw_device_descriptor dv_pal_descriptor[];
-const struct hw_device_descriptor *hw_descriptors[] = {
-  dv_core_descriptor,
-  dv_pal_descriptor,
-  NULL,
-};
-
 #ifdef HAVE_STRING_H
 #include <string.h>
 #else
@@ -46,6 +37,8 @@ const struct hw_device_descriptor *hw_descriptors[] = {
 
 #include <ctype.h>
 
+#include "hw-config.h"
+
 struct hw_base_data {
   int finished_p;
   const struct hw_device_descriptor *descriptor;
@@ -222,9 +215,7 @@ panic_hw_io_read_buffer (struct hw *me,
                         void *dest,
                         int space,
                         unsigned_word addr,
-                        unsigned nr_bytes,
-                        sim_cpu *processor,
-                        sim_cia cia)
+                        unsigned nr_bytes)
 {
   hw_abort (me, "no io-read method");
   return 0;
@@ -235,9 +226,7 @@ panic_hw_io_write_buffer (struct hw *me,
                          const void *source,
                          int space,
                          unsigned_word addr,
-                         unsigned nr_bytes,
-                         sim_cpu *processor,
-                         sim_cia cia)
+                         unsigned nr_bytes)
 {
   hw_abort (me, "no io-write method");
   return 0;
@@ -272,22 +261,6 @@ passthrough_hw_dma_write_buffer (struct hw *me,
                              violate_read_only_section);
 }
 
-const struct hw_port_descriptor empty_hw_ports[] = {
-  { NULL, },
-};
-
-static void
-panic_hw_port_event (struct hw *me,
-                    int my_port,
-                    struct hw *source,
-                    int source_port,
-                    int level,
-                    sim_cpu *processor,
-                    sim_cia cia)
-{
-  hw_abort (me, "no port method");
-}
-
 static void
 ignore_hw_delete (struct hw *me)
 {
@@ -342,12 +315,12 @@ full_name_of_hw (struct hw *leaf,
   
   /* return it usefully */
   if (buf == full_name)
-    buf = (char *) strdup (full_name);
+    buf = hw_strdup (leaf, full_name);
   return buf;
 }
 
 struct hw *
-hw_create (SIM_DESC sd,
+hw_create (struct sim_state *sd,
           struct hw *parent,
           const char *family,
           const char *name,
@@ -358,9 +331,9 @@ hw_create (SIM_DESC sd,
   struct hw *hw = ZALLOC (struct hw);
 
   /* our identity */
-  hw->family_of_hw = family;
-  hw->name_of_hw = name;
-  hw->args_of_hw = args;
+  hw->family_of_hw = hw_strdup (hw, family);
+  hw->name_of_hw = hw_strdup (hw, name);
+  hw->args_of_hw = hw_strdup (hw, args);
 
   /* a hook into the system */
   if (sd != NULL)
@@ -433,6 +406,7 @@ hw_create (SIM_DESC sd,
            if (strcmp (family, entry->family) == 0)
              {
                hw->base_of_hw->descriptor = entry;
+               break;
              }
          }
       }
@@ -443,8 +417,7 @@ hw_create (SIM_DESC sd,
   }
 
   /* Attach dummy ports */
-  set_hw_ports (hw, empty_hw_ports);
-  set_hw_port_event (hw, panic_hw_port_event);
+  create_hw_port_data (hw);
   
   return hw;
 }
@@ -477,6 +450,12 @@ hw_finish (struct hw *me)
   /* Fill in the (hopefully) defined trace variable */
   if (hw_find_property (me, "trace?") != NULL)
     me->trace_of_hw_p = hw_find_boolean_property (me, "trace?");
+  /* allow global variable to define default tracing */
+  else if (! hw_trace_p (me)
+          && hw_find_property (hw_root (me), "global-trace?") != NULL
+          && hw_find_boolean_property (hw_root (me), "global-trace?"))
+    me->trace_of_hw_p = 1;
+    
 
   /* Allow the real device to override any methods */
   me->base_of_hw->descriptor->to_finish (me);
@@ -490,6 +469,8 @@ hw_delete (struct hw *me)
   /* give the object a chance to tidy up */
   me->base_of_hw->to_delete (me);
 
+  delete_hw_port_data (me);
+
   /* now unlink us from the tree */
   if (hw_parent (me))
     {
index ee787dd76e635c433f814cb4c1252805e785e082..27702c8c88752993dabd299b55564a5c75854fb7 100644 (file)
@@ -42,7 +42,7 @@ struct hw_device_descriptor {
 /* Create a primative device */
 
 struct hw *hw_create
-(SIM_DESC sd,
+(struct sim_state *sd,
  struct hw *parent,
  const char *family,
  const char *name,
@@ -106,23 +106,38 @@ typedef void (hw_delete_callback)
 ((hw)->base_of_hw->to_delete = (method))
 
 
-struct hw_port_descriptor {
-  const char *name;
-  int number; 
-  int nr_ports;
-  port_direction direction;
+/* Helper functions to make the implementation of a device easier */
+
+/* Go through the devices reg properties and look for those specifying
+   an address to attach various registers to */
+
+void do_hw_attach_regs (struct hw *me);
+
+/* Perform a polling read on FD returning either the number of bytes
+   or a hw_io status code that indicates the reason for the read
+   failure */
+
+enum {
+  HW_IO_EOF = -1, HW_IO_NOT_READY = -2, /* See: IEEE 1275 */
 };
 
-typedef void (hw_port_event_callback)
-     (struct hw *me,
-      int my_port,
-      struct hw *source,
-      int source_port,
-      int level,
-      sim_cpu *processor,
-      sim_cia cia);
-
-extern void set_hw_ports (struct hw *hw, const struct hw_port_descriptor ports[]);
-extern void set_hw_port_event (struct hw *hw, hw_port_event_callback *to_port_event);
+typedef int (do_hw_poll_read_method)
+     (SIM_DESC sd, int, char *, int);
+
+int do_hw_poll_read
+(struct hw *me,
+ do_hw_poll_read_method *read,
+ int sim_io_fd,
+ void *buf,
+ unsigned size_of_buf);
+
+
+/* PORTS */
+
+extern void create_hw_port_data
+(struct hw *hw);
+extern void delete_hw_port_data
+(struct hw *hw);
+
 
 #endif
diff --git a/sim/common/hw-ports.c b/sim/common/hw-ports.c
new file mode 100644 (file)
index 0000000..4144bc7
--- /dev/null
@@ -0,0 +1,339 @@
+/* Common hardware.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   Contributed by Andrew Cagney and Cygnus Solutions.
+
+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 "hw-base.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+#include <ctype.h>
+
+#define TRACE(x,y)
+
+
+struct hw_port_edge {
+  int my_port;
+  struct hw *dest;
+  int dest_port;
+  struct hw_port_edge *next;
+  object_disposition disposition;
+};
+
+struct hw_port_data {
+  hw_port_event_callback *to_port_event;
+  const struct hw_port_descriptor *ports;
+  struct hw_port_edge *edges;
+};
+
+const struct hw_port_descriptor empty_hw_ports[] = {
+  { NULL, },
+};
+
+static void
+panic_hw_port_event (struct hw *me,
+                    int my_port,
+                    struct hw *source,
+                    int source_port,
+                    int level)
+{
+  hw_abort (me, "no port method");
+}
+
+void
+create_hw_port_data (struct hw *me)
+{
+  me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data);
+  set_hw_port_event (me, panic_hw_port_event);
+  set_hw_ports (me, empty_hw_ports);
+}
+
+void
+delete_hw_port_data (struct hw *me)
+{
+  hw_free (me, me->ports_of_hw);
+  me->ports_of_hw = NULL;
+}
+
+void
+set_hw_ports (struct hw *me,
+             const struct hw_port_descriptor ports[])
+{
+  me->ports_of_hw->ports = ports;
+}
+
+void
+set_hw_port_event (struct hw *me,
+                  hw_port_event_callback *port_event)
+{
+  me->ports_of_hw->to_port_event = port_event;
+}
+
+
+static void
+attach_hw_port_edge (struct hw *me,
+                    struct hw_port_edge **list,
+                    int my_port,
+                    struct hw *dest,
+                    int dest_port,
+                    object_disposition disposition)
+{
+  struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge);
+  new_edge->my_port = my_port;
+  new_edge->dest = dest;
+  new_edge->dest_port = dest_port;
+  new_edge->next = *list;
+  new_edge->disposition = disposition;
+  *list = new_edge;
+}
+
+
+static void
+detach_hw_port_edge (struct hw *me,
+                    struct hw_port_edge **list,
+                    int my_port,
+                    struct hw *dest,
+                    int dest_port)
+{
+  while (*list != NULL)
+    {
+      struct hw_port_edge *old_edge = *list;
+      if (old_edge->dest == dest
+         && old_edge->dest_port == dest_port
+         && old_edge->my_port == my_port)
+       {
+         if (old_edge->disposition == permenant_object)
+           hw_abort (me, "attempt to delete permenant port edge");
+         *list = old_edge->next;
+         hw_free (me, old_edge);
+         return;
+       }
+    }
+  hw_abort (me, "attempt to delete unattached port");
+}
+
+
+#if 0
+static void
+clean_hw_port_edges (struct hw_port_edge **list)
+{
+  while (*list != NULL)
+    {
+      struct hw_port_edge *old_edge = *list;
+      switch (old_edge->disposition)
+       {
+       case permenant_object:
+         list = &old_edge->next;
+         break;
+       case temporary_object:
+         *list = old_edge->next;
+         hw_free (me, old_edge);
+         break;
+       }
+    }
+}
+#endif
+
+
+/* Ports: */
+
+void
+hw_port_event (struct hw *me,
+              int my_port,
+              int level)
+{
+  int found_an_edge = 0;
+  struct hw_port_edge *edge;
+  /* device's lines directly connected */
+  for (edge = me->ports_of_hw->edges;
+       edge != NULL;
+       edge = edge->next)
+    {
+      if (edge->my_port == my_port)
+       {
+         edge->dest->ports_of_hw->to_port_event (edge->dest,
+                                                 edge->dest_port,
+                                                 me,
+                                                 my_port,
+                                                 level);
+         found_an_edge = 1;
+       }
+    }
+  if (!found_an_edge)
+    hw_abort (me, "No edge for port %d", my_port);
+}
+
+
+void
+hw_port_attach (struct hw *me,
+               int my_port,
+               struct hw *dest,
+               int dest_port,
+               object_disposition disposition)
+{
+  attach_hw_port_edge (me,
+                      &me->ports_of_hw->edges,
+                      my_port,
+                      dest,
+                      dest_port,
+                      disposition);
+}
+
+
+void
+hw_port_detach (struct hw *me,
+               int my_port,
+               struct hw *dest,
+               int dest_port)
+{
+  detach_hw_port_edge (me,
+                      &me->ports_of_hw->edges,
+                      my_port,
+                      dest,
+                      dest_port);
+}
+
+
+void
+hw_port_traverse (struct hw *me,
+                 hw_port_traverse_function *handler,
+                 void *data)
+{
+  struct hw_port_edge *port_edge;
+  for (port_edge = me->ports_of_hw->edges;
+       port_edge != NULL;
+       port_edge = port_edge->next)
+    {
+      handler (me, port_edge->my_port,
+              port_edge->dest, port_edge->dest_port,
+              data);
+    }
+}
+
+
+int
+hw_port_decode (struct hw *me,
+               const char *port_name,
+               port_direction direction)
+{
+  if (port_name == NULL || port_name[0] == '\0')
+    return 0;
+  if (isdigit(port_name[0]))
+    {
+      return strtoul (port_name, NULL, 0);
+    }
+  else
+    {
+      const struct hw_port_descriptor *ports =
+       me->ports_of_hw->ports;
+      if (ports != NULL) 
+       {
+         while (ports->name != NULL)
+           {
+             if (ports->direction == bidirect_port
+                 || ports->direction == direction)
+               {
+                 if (ports->nr_ports > 0)
+                   {
+                     int len = strlen (ports->name);
+                     if (strncmp (port_name, ports->name, len) == 0)
+                       {
+                         if (port_name[len] == '\0')
+                           return ports->number;
+                         else if(isdigit (port_name[len]))
+                           {
+                             int port = (ports->number
+                                         + strtoul (&port_name[len], NULL, 0));
+                             if (port >= ports->number + ports->nr_ports)
+                               hw_abort (me,
+                                         "Port %s out of range",
+                                         port_name);
+                             return port;
+                           }
+                       }
+                   }
+                 else if (strcmp (port_name, ports->name) == 0)
+                   return ports->number;
+               }
+             ports++;
+           }
+       }
+    }
+  hw_abort (me, "Unreconized port %s", port_name);
+  return 0;
+}
+
+
+int
+hw_port_encode (struct hw *me,
+               int port_number,
+               char *buf,
+               int sizeof_buf,
+               port_direction direction)
+{
+  const struct hw_port_descriptor *ports = NULL;
+  ports = me->ports_of_hw->ports;
+  if (ports != NULL) {
+    while (ports->name != NULL)
+      {
+       if (ports->direction == bidirect_port
+           || ports->direction == direction)
+         {
+           if (ports->nr_ports > 0)
+             {
+               if (port_number >= ports->number
+                   && port_number < ports->number + ports->nr_ports)
+                 {
+                   strcpy (buf, ports->name);
+                   sprintf (buf + strlen(buf), "%d", port_number - ports->number);
+                   if (strlen (buf) >= sizeof_buf)
+                     hw_abort (me, "hw_port_encode: buffer overflow");
+                   return strlen (buf);
+                 }
+             }
+           else
+             {
+               if (ports->number == port_number)
+                 {
+                   if (strlen(ports->name) >= sizeof_buf)
+                     hw_abort (me, "hw_port_encode: buffer overflow");
+                   strcpy(buf, ports->name);
+                   return strlen(buf);
+                 }
+             }
+         }
+       ports++;
+      }
+  }
+  sprintf (buf, "%d", port_number);
+  if (strlen(buf) >= sizeof_buf)
+    hw_abort (me, "hw_port_encode: buffer overflow");
+  return strlen(buf);
+}
diff --git a/sim/common/hw-ports.h b/sim/common/hw-ports.h
new file mode 100644 (file)
index 0000000..79357c4
--- /dev/null
@@ -0,0 +1,129 @@
+/* Common hardware.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   Contributed by Andrew Cagney and Cygnus Solutions.
+
+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.  */
+
+
+#ifndef HW_PORTS_H
+#define HW_PORTS_H
+
+/* Initialize a port */
+
+struct hw_port_descriptor {
+  const char *name;
+  int number; 
+  int nr_ports;
+  port_direction direction;
+};
+
+void set_hw_ports (struct hw *hw, const struct hw_port_descriptor ports[]);
+
+typedef void (hw_port_event_callback)
+     (struct hw *me,
+      int my_port,
+      struct hw *source,
+      int source_port,
+      int level);
+
+void set_hw_port_event (struct hw *hw, hw_port_event_callback *to_port_event);
+
+
+/* Port source
+
+   A device drives its output ports using the call
+
+   */
+
+void hw_port_event
+(struct hw *me,
+ int my_port,
+ int value);
+
+/* This port event will then be propogated to any attached
+   destination ports.
+
+   Any interpretation of PORT and VALUE is model dependant.  As a
+   guideline the following are recommended: PCI interrupts A-D should
+   correspond to ports 0-3; level sensative interrupts be requested
+   with a value of one and withdrawn with a value of 0; edge sensative
+   interrupts always have a value of 1, the event its self is treated
+   as the interrupt.
+
+
+   Port destinations
+
+   Attached to each port of a device can be zero or more
+   desitinations.  These destinations consist of a device/port pair.
+   A destination is attached/detached to a device line using the
+   attach and detach calls. */
+
+void hw_port_attach
+(struct hw *me,
+ int my_port,
+ struct hw *dest,
+ int dest_port,
+ object_disposition disposition);
+
+void hw_port_detach
+(struct hw *me,
+ int my_port,
+ struct hw *dest,
+ int dest_port);
+
+
+/* Iterate over the list of ports attached to a device */
+
+typedef void (hw_port_traverse_function)
+     (struct hw *me,
+      int my_port,
+      struct hw *dest,
+      int dest_port,
+      void *data);
+
+void hw_port_traverse
+(struct hw *me,
+ hw_port_traverse_function *handler,
+ void *data);
+
+/* DESTINATION is attached (detached) to LINE of the device ME
+
+
+   Port conversion
+
+   Users refer to port numbers symbolically.  For instance a device
+   may refer to its `INT' signal which is internally represented by
+   port 3.
+
+   To convert to/from the symbolic and internal representation of a
+   port name/number.  The following functions are available. */
+
+int hw_port_decode
+(struct hw *me,
+ const char *symbolic_name,
+ port_direction direction);
+
+int hw_port_encode
+(struct hw *me,
+ int port_number,
+ char *buf,
+ int sizeof_buf,
+ port_direction direction);
+
+#endif