diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog index 9f0aa26e30..d8e1cea3a5 100644 --- a/sim/common/ChangeLog +++ b/sim/common/ChangeLog @@ -1,3 +1,16 @@ +Mon May 25 16:55:16 1998 Andrew Cagney + + * 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 * hw-device.c (hw_ioctl), hw-device.h (hw_ioctl_callback): Drop diff --git a/sim/common/hw-base.c b/sim/common/hw-base.c index 8a5a299045..e8c09f064b 100644 --- a/sim/common/hw-base.c +++ b/sim/common/hw-base.c @@ -23,15 +23,6 @@ #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 #else @@ -46,6 +37,8 @@ const struct hw_device_descriptor *hw_descriptors[] = { #include +#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)) { diff --git a/sim/common/hw-base.h b/sim/common/hw-base.h index ee787dd76e..27702c8c88 100644 --- a/sim/common/hw-base.h +++ b/sim/common/hw-base.h @@ -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); +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); -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); #endif diff --git a/sim/common/hw-ports.c b/sim/common/hw-ports.c new file mode 100644 index 0000000000..4144bc7c15 --- /dev/null +++ b/sim/common/hw-ports.c @@ -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 +#endif + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +#include + +#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 index 0000000000..79357c4546 --- /dev/null +++ b/sim/common/hw-ports.h @@ -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