aboutsummaryrefslogtreecommitdiff
path: root/sim/common
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>1998-03-22 04:18:52 +0000
committerAndrew Cagney <cagney@redhat.com>1998-03-22 04:18:52 +0000
commitb1e9223cee0728b89f6b909c445a896d9fe41452 (patch)
treeb38bb06b7ec6075dcebfca1705743b29cc5a79be /sim/common
parent6cfaad4d884e380f3a0f9aa06618bcda1e5762d3 (diff)
downloadgdb-b1e9223cee0728b89f6b909c445a896d9fe41452.zip
gdb-b1e9223cee0728b89f6b909c445a896d9fe41452.tar.gz
gdb-b1e9223cee0728b89f6b909c445a896d9fe41452.tar.bz2
Replace *attach_address() arguments SPACEMASK:ADDR with SPACE:ADDR.
Add notes to hw-device.h that discuss the interpretation of SPACE:ADDR on a BUS.
Diffstat (limited to 'sim/common')
-rw-r--r--sim/common/ChangeLog15
-rw-r--r--sim/common/dv-core.c116
-rw-r--r--sim/common/dv-pal.c387
-rw-r--r--sim/common/hw-base.c467
-rw-r--r--sim/common/hw-device.h496
5 files changed, 1481 insertions, 0 deletions
diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog
index dda6f5c..65499fd 100644
--- a/sim/common/ChangeLog
+++ b/sim/common/ChangeLog
@@ -1,3 +1,18 @@
+Sun Mar 22 15:09:52 1998 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * hw-device.h (hw_attach_address_callback,
+ hw_detach_address_callback): Attach to a single space not a space
+ mask. Clarify interpretation of SPACE:ADDR parameters.
+
+ * hw-base.c (passthrough_hw_attach_address,
+ passthrough_hw_detach_address): Update.
+ * dv-core.c (dv_core_attach_address_callback): Ditto.
+ * dv-pal.c (hw_pal_attach_address): Ditto.
+
+Thu Mar 19 00:41:00 1998 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * sim-options.h: Document additional CPU arg to OPTION_HANDLER.
+
Wed Mar 18 14:13:02 1998 Andrew Cagney <cagney@b1.cygnus.com>
* Make-common.in (SIM_HW_OBJS, SIM_HW_SRC, SIM_DV_OBJS): Define.
diff --git a/sim/common/dv-core.c b/sim/common/dv-core.c
new file mode 100644
index 0000000..bdb612c
--- /dev/null
+++ b/sim/common/dv-core.c
@@ -0,0 +1,116 @@
+/* This file is part of the program psim.
+
+ Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
+
+ 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 of the License, 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"
+
+/* DEVICE
+
+ core - root of the device tree
+
+ DESCRIPTION
+
+ The core device, positioned at the root of the device tree appears
+ to its child devices as a normal device just like every other
+ device in the tree.
+
+ Internally it is implemented using a core object. Requests to
+ attach (or detach) address spaces are passed to that core object.
+ Requests to transfer (DMA) data are reflected back down the device
+ tree using the core_map data transfer methods.
+
+ PROPERTIES
+
+ None.
+
+ */
+
+
+static void
+dv_core_attach_address_callback (struct hw *me,
+ int level,
+ int space,
+ address_word addr,
+ address_word nr_bytes,
+ struct hw *client)
+{
+ /* NOTE: At preset the space is assumed to be zero. Perhaphs the
+ space should be mapped onto something for instance: space0 -
+ unified memory; space1 - IO memory; ... */
+ if (space != 0)
+ hw_abort (me, "Hey! Unknown space %d", space);
+ sim_core_attach (hw_system (me),
+ NULL, /*cpu*/
+ level,
+ access_read_write_exec,
+ space, addr,
+ nr_bytes,
+ 0, /* modulo */
+ client,
+ NULL);
+}
+
+
+static unsigned
+dv_core_dma_read_buffer_callback (struct hw *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ return sim_core_read_buffer (hw_system (me),
+ NULL, /*CPU*/
+ space, /*???*/
+ dest,
+ addr,
+ nr_bytes);
+}
+
+
+static unsigned
+dv_core_dma_write_buffer_callback (struct hw *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ return sim_core_write_buffer (hw_system (me),
+ NULL, /*cpu*/
+ space, /*???*/
+ source,
+ addr,
+ nr_bytes);
+}
+
+
+static void
+dv_core_finish (struct hw *me)
+{
+ set_hw_attach_address (me, dv_core_attach_address_callback);
+ set_hw_dma_write_buffer (me, dv_core_dma_write_buffer_callback);
+ set_hw_dma_read_buffer (me, dv_core_dma_read_buffer_callback);
+}
+
+const struct hw_device_descriptor dv_core_descriptor[] = {
+ { "core", dv_core_finish, },
+ { NULL },
+};
diff --git a/sim/common/dv-pal.c b/sim/common/dv-pal.c
new file mode 100644
index 0000000..afef9c8
--- /dev/null
+++ b/sim/common/dv-pal.c
@@ -0,0 +1,387 @@
+/* This file is part of the program psim.
+
+ Copyright (C) 1994-1996,1998, Andrew Cagney <cagney@highland.com.au>
+
+ 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 of the License, 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"
+
+/* NOTE: pal is naughty and grubs around looking at things outside of
+ its immediate domain */
+#include "hw-tree.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#define DTRACE(x,y)
+
+/* DEVICE
+
+
+ pal - glue logic device containing assorted junk
+
+
+ DESCRIPTION
+
+
+ Typical hardware dependant hack. This device allows the firmware
+ to gain access to all the things the firmware needs (but the OS
+ doesn't).
+
+ The pal contains the following registers. Except for the interrupt
+ level register, each of the below is 8 bytes in size and must be
+ accessed using correct alignment. For 16 and 32 bit accesses the
+ bytes not directed to the register are ignored:
+
+ |0 reset register (write)
+ |4 processor id register (read)
+ |8 interrupt port (write)
+ |9 interrupt level (write)
+ |12 processor count register (read)
+ |16 tty input fifo register (read)
+ |20 tty input status register (read)
+ |24 tty output fifo register (write)
+ |28 tty output status register (read)
+
+ Reset register (write) halts the simulator exiting with the
+ value written.
+
+ Processor id register (read) returns the processor number (0
+ .. N-1) of the processor performing the read.
+
+ The interrupt registers should be accessed as a pair (using a 16 or
+ 32 bit store). The low byte specifies the interrupt port while the
+ high byte specifies the level to drive that port at. By
+ convention, the pal's interrupt ports (int0, int1, ...) are wired
+ up to the corresponding processor's level sensative external
+ interrupt pin. Eg: A two byte write to address 8 of 0x0102
+ (big-endian) will result in processor 2's external interrupt pin to
+ be asserted.
+
+ Processor count register (read) returns the total number of
+ processors active in the current simulation.
+
+ TTY input fifo register (read), if the TTY input status register
+ indicates a character is available by being nonzero, returns the
+ next available character from the pal's tty input port.
+
+ Similarly, the TTY output fifo register (write), if the TTY output
+ status register indicates the output fifo is not full by being
+ nonzero, outputs the character written to the tty's output port.
+
+
+ PROPERTIES
+
+
+ reg = <address> <size> (required)
+
+ Specify the address (within the parent bus) that this device is to
+ live.
+
+
+ */
+
+
+enum {
+ hw_pal_reset_register = 0x0,
+ hw_pal_cpu_nr_register = 0x4,
+ hw_pal_int_register = 0x8,
+ hw_pal_nr_cpu_register = 0xa,
+ hw_pal_read_fifo = 0x10,
+ hw_pal_read_status = 0x14,
+ hw_pal_write_fifo = 0x18,
+ hw_pal_write_status = 0x1a,
+ hw_pal_address_mask = 0x1f,
+};
+
+
+typedef struct _hw_pal_console_buffer {
+ char buffer;
+ int status;
+} hw_pal_console_buffer;
+
+typedef struct _hw_pal_device {
+ hw_pal_console_buffer input;
+ hw_pal_console_buffer output;
+ struct hw *disk;
+} hw_pal_device;
+
+
+/* check the console for an available character */
+static void
+scan_hw_pal (struct hw *me)
+{
+#if 0
+ hw_pal_struct hw *hw_pal = (hw_pal_struct hw *) hw_data (me);
+#endif
+ char c;
+ int count;
+ count = sim_io_read_stdin (hw_system (me), &c, sizeof(c));
+#if 0
+ switch (count)
+ {
+ case sim_io_not_ready:
+ case sim_io_eof:
+ hw_pal->input.buffer = 0;
+ hw_pal->input.status = 0;
+ break;
+ default:
+ hw_pal->input.buffer = c;
+ hw_pal->input.status = 1;
+ }
+#endif
+}
+
+/* write the character to the hw_pal */
+static void
+write_hw_pal (struct hw *me,
+ char val)
+{
+ hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
+ sim_io_write_stdout (hw_system (me), &val, 1);
+ hw_pal->output.buffer = val;
+ hw_pal->output.status = 1;
+}
+
+
+static unsigned
+hw_pal_io_read_buffer (struct hw *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ sim_cpu *cpu,
+ sim_cia cia)
+{
+ hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
+ unsigned_1 val;
+ switch (addr & hw_pal_address_mask)
+ {
+ case hw_pal_cpu_nr_register:
+#ifdef CPU_INDEX
+ val = CPU_INDEX (cpu);
+#else
+ val = 0;
+#endif
+ DTRACE (pal, ("read - cpu-nr %d\n", val));
+ break;
+ case hw_pal_nr_cpu_register:
+ val = hw_tree_find_integer_property (me, "/openprom/options/smp");
+ DTRACE (pal, ("read - nr-cpu %d\n", val));
+ break;
+ case hw_pal_read_fifo:
+ val = hw_pal->input.buffer;
+ DTRACE (pal, ("read - input-fifo %d\n", val));
+ break;
+ case hw_pal_read_status:
+ scan_hw_pal (me);
+ val = hw_pal->input.status;
+ DTRACE (pal, ("read - input-status %d\n", val));
+ break;
+ case hw_pal_write_fifo:
+ val = hw_pal->output.buffer;
+ DTRACE (pal, ("read - output-fifo %d\n", val));
+ break;
+ case hw_pal_write_status:
+ val = hw_pal->output.status;
+ DTRACE (pal, ("read - output-status %d\n", val));
+ break;
+ default:
+ val = 0;
+ DTRACE (pal, ("read - ???\n"));
+ }
+ memset (dest, 0, nr_bytes);
+ *(unsigned_1*)dest = val;
+ return nr_bytes;
+}
+
+
+static unsigned
+hw_pal_io_write_buffer (struct hw *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ sim_cpu *cpu,
+ sim_cia cia)
+{
+ hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me);
+ unsigned_1 *byte = (unsigned_1*) source;
+
+ switch (addr & hw_pal_address_mask)
+ {
+ case hw_pal_reset_register:
+ sim_engine_halt (NULL, cpu, NULL, cia, sim_exited, byte[0]);
+ break;
+ case hw_pal_int_register:
+ hw_port_event (me,
+ byte[0], /*port*/
+ (nr_bytes > 1 ? byte[1] : 0), /* val */
+ cpu, cia);
+ break;
+ case hw_pal_read_fifo:
+ hw_pal->input.buffer = byte[0];
+ DTRACE (pal, ("write - input-fifo %d\n", byte[0]));
+ break;
+ case hw_pal_read_status:
+ hw_pal->input.status = byte[0];
+ DTRACE (pal, ("write - input-status %d\n", byte[0]));
+ break;
+ case hw_pal_write_fifo:
+ write_hw_pal (me, byte[0]);
+ DTRACE (pal, ("write - output-fifo %d\n", byte[0]));
+ break;
+ case hw_pal_write_status:
+ hw_pal->output.status = byte[0];
+ DTRACE (pal, ("write - output-status %d\n", byte[0]));
+ break;
+ }
+ return nr_bytes;
+}
+
+
+/* instances of the hw_pal struct hw */
+
+#if NOT_YET
+static void
+hw_pal_instance_delete_callback(hw_instance *instance)
+{
+ /* nothing to delete, the hw_pal is attached to the struct hw */
+ return;
+}
+#endif
+
+#if NOT_YET
+static int
+hw_pal_instance_read_callback (hw_instance *instance,
+ void *buf,
+ unsigned_word len)
+{
+ DITRACE (pal, ("read - %s (%ld)", (const char*) buf, (long int) len));
+ return sim_io_read_stdin (buf, len);
+}
+#endif
+
+#if NOT_YET
+static int
+hw_pal_instance_write_callback (hw_instance *instance,
+ const void *buf,
+ unsigned_word len)
+{
+ int i;
+ const char *chp = buf;
+ hw_pal_device *hw_pal = hw_instance_data (instance);
+ DITRACE (pal, ("write - %s (%ld)", (const char*) buf, (long int) len));
+ for (i = 0; i < len; i++)
+ write_hw_pal (hw_pal, chp[i]);
+ sim_io_flush_stdoutput ();
+ return i;
+}
+#endif
+
+#if NOT_YET
+static const hw_instance_callbacks hw_pal_instance_callbacks = {
+ hw_pal_instance_delete_callback,
+ hw_pal_instance_read_callback,
+ hw_pal_instance_write_callback,
+};
+#endif
+
+#if 0
+static hw_instance *
+hw_pal_create_instance (struct hw *me,
+ const char *path,
+ const char *args)
+{
+ return hw_create_instance_from (me, NULL,
+ hw_data (me),
+ path, args,
+ &hw_pal_instance_callbacks);
+}
+#endif
+
+static const struct hw_port_descriptor hw_pal_ports[] = {
+ { "int", 0, MAX_NR_PROCESSORS },
+ { NULL }
+};
+
+
+static void
+hw_pal_attach_address (struct hw *me,
+ int level,
+ int space,
+ address_word addr,
+ address_word nr_bytes,
+ struct hw *client)
+{
+ hw_pal_device *pal = (hw_pal_device*) hw_data (me);
+ pal->disk = client;
+}
+
+
+#if 0
+static hw_callbacks const hw_pal_callbacks = {
+ { generic_hw_init_address, },
+ { hw_pal_attach_address, }, /* address */
+ { hw_pal_io_read_buffer_callback,
+ hw_pal_io_write_buffer_callback, },
+ { NULL, }, /* DMA */
+ { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
+ { generic_hw_unit_decode,
+ generic_hw_unit_encode,
+ generic_hw_address_to_attach_address,
+ generic_hw_size_to_attach_size },
+ hw_pal_create_instance,
+};
+#endif
+
+
+static void
+hw_pal_finish (struct hw *hw)
+{
+ /* create the descriptor */
+ hw_pal_device *hw_pal = ZALLOC (hw_pal_device);
+ hw_pal->output.status = 1;
+ hw_pal->output.buffer = '\0';
+ hw_pal->input.status = 0;
+ hw_pal->input.buffer = '\0';
+ set_hw_data (hw, hw_pal);
+ set_hw_attach_address (hw, hw_pal_attach_address);
+ set_hw_io_read_buffer (hw, hw_pal_io_read_buffer);
+ set_hw_io_write_buffer (hw, hw_pal_io_write_buffer);
+ set_hw_ports (hw, hw_pal_ports);
+}
+
+
+const struct hw_device_descriptor dv_pal_descriptor[] = {
+ { "pal", hw_pal_finish, },
+ { NULL },
+};
diff --git a/sim/common/hw-base.c b/sim/common/hw-base.c
new file mode 100644
index 0000000..0c4b8a5
--- /dev/null
+++ b/sim/common/hw-base.c
@@ -0,0 +1,467 @@
+/* This file is part of the program psim.
+
+ Copyright (C) 1994-1996, 1998, Andrew Cagney <cagney@highland.com.au>
+
+ 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 of the License, 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"
+
+
+/* LATER: #include "hwconfig.h" */
+struct hw_base_data {
+ int finished_p;
+ const struct hw_device_descriptor *descriptor;
+};
+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
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <ctype.h>
+
+
+static int
+generic_hw_unit_decode (struct hw *bus,
+ const char *unit,
+ hw_unit *phys)
+{
+ memset (phys, 0, sizeof (*phys));
+ if (unit == NULL)
+ return 0;
+ else
+ {
+ int nr_cells = 0;
+ const int max_nr_cells = hw_unit_nr_address_cells (bus);
+ while (1)
+ {
+ char *end = NULL;
+ unsigned long val;
+ val = strtoul (unit, &end, 0);
+ /* parse error? */
+ if (unit == end)
+ return -1;
+ /* two many cells? */
+ if (nr_cells >= max_nr_cells)
+ return -1;
+ /* save it */
+ phys->cells[nr_cells] = val;
+ nr_cells++;
+ unit = end;
+ /* more to follow? */
+ if (isspace (*unit) || *unit == '\0')
+ break;
+ if (*unit != ',')
+ return -1;
+ unit++;
+ }
+ if (nr_cells < max_nr_cells) {
+ /* shift everything to correct position */
+ int i;
+ for (i = 1; i <= nr_cells; i++)
+ phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
+ for (i = 0; i < (max_nr_cells - nr_cells); i++)
+ phys->cells[i] = 0;
+ }
+ phys->nr_cells = max_nr_cells;
+ return max_nr_cells;
+ }
+}
+
+static int
+generic_hw_unit_encode (struct hw *bus,
+ const hw_unit *phys,
+ char *buf,
+ int sizeof_buf)
+{
+ int i;
+ int len;
+ char *pos = buf;
+ /* skip leading zero's */
+ for (i = 0; i < phys->nr_cells; i++)
+ {
+ if (phys->cells[i] != 0)
+ break;
+ }
+ /* don't output anything if empty */
+ if (phys->nr_cells == 0)
+ {
+ strcpy(pos, "");
+ len = 0;
+ }
+ else if (i == phys->nr_cells)
+ {
+ /* all zero */
+ strcpy(pos, "0");
+ len = 1;
+ }
+ else
+ {
+ for (; i < phys->nr_cells; i++)
+ {
+ if (pos != buf) {
+ strcat(pos, ",");
+ pos = strchr(pos, '\0');
+ }
+ if (phys->cells[i] < 10)
+ sprintf (pos, "%ld", (unsigned long)phys->cells[i]);
+ else
+ sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]);
+ pos = strchr(pos, '\0');
+ }
+ len = pos - buf;
+ }
+ if (len >= sizeof_buf)
+ hw_abort (NULL, "generic_unit_encode - buffer overflow\n");
+ return len;
+}
+
+static int
+generic_hw_unit_address_to_attach_address (struct hw *me,
+ const hw_unit *address,
+ int *attach_space,
+ unsigned_word *attach_address,
+ struct hw *client)
+{
+ int i;
+ for (i = 0; i < address->nr_cells - 2; i++)
+ {
+ if (address->cells[i] != 0)
+ hw_abort (me, "Only 32bit addresses supported");
+ }
+ if (address->nr_cells >= 2)
+ *attach_space = address->cells[address->nr_cells - 2];
+ else
+ *attach_space = 0;
+ *attach_address = address->cells[address->nr_cells - 1];
+ return 1;
+}
+
+static int
+generic_hw_unit_size_to_attach_size (struct hw *me,
+ const hw_unit *size,
+ unsigned *nr_bytes,
+ struct hw *client)
+{
+ int i;
+ for (i = 0; i < size->nr_cells - 1; i++)
+ {
+ if (size->cells[i] != 0)
+ hw_abort (me, "Only 32bit sizes supported");
+ }
+ *nr_bytes = size->cells[0];
+ return *nr_bytes;
+}
+
+
+/* ignore/passthrough versions of each function */
+
+static void
+passthrough_hw_attach_address (struct hw *me,
+ int level,
+ int space,
+ address_word addr,
+ address_word nr_bytes,
+ struct hw *client) /*callback/default*/
+{
+ if (hw_parent (me) == NULL)
+ hw_abort (client, "hw_attach_address: no parent attach method");
+ hw_attach_address (hw_parent (me), level,
+ space, addr, nr_bytes,
+ client);
+}
+
+static void
+passthrough_hw_detach_address (struct hw *me,
+ int level,
+ int space,
+ address_word addr,
+ address_word nr_bytes,
+ struct hw *client) /*callback/default*/
+{
+ if (hw_parent (me) == NULL)
+ hw_abort (client, "hw_attach_address: no parent attach method");
+ hw_detach_address (hw_parent (me), level,
+ space, addr, nr_bytes,
+ client);
+}
+
+static unsigned
+panic_hw_io_read_buffer (struct hw *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ sim_cpu *processor,
+ sim_cia cia)
+{
+ hw_abort (me, "no io-read method");
+ return 0;
+}
+
+static unsigned
+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)
+{
+ hw_abort (me, "no io-write method");
+ return 0;
+}
+
+static unsigned
+passthrough_hw_dma_read_buffer (struct hw *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ if (hw_parent (me) == NULL)
+ hw_abort (me, "no parent dma-read method");
+ return hw_dma_read_buffer (hw_parent (me), dest,
+ space, addr, nr_bytes);
+}
+
+static unsigned
+passthrough_hw_dma_write_buffer (struct hw *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ if (hw_parent (me) == NULL)
+ hw_abort (me, "no parent dma-write method");
+ return hw_dma_write_buffer (hw_parent (me), source,
+ space, addr,
+ nr_bytes,
+ 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 const char *
+full_name_of_hw (struct hw *leaf,
+ char *buf,
+ unsigned sizeof_buf)
+{
+ /* get a buffer */
+ char full_name[1024];
+ if (buf == (char*)0)
+ {
+ buf = full_name;
+ sizeof_buf = sizeof (full_name);
+ }
+
+ /* use head recursion to construct the path */
+
+ if (hw_parent (leaf) == NULL)
+ /* root */
+ {
+ if (sizeof_buf < 1)
+ hw_abort (leaf, "buffer overflow");
+ *buf = '\0';
+ }
+ else
+ /* sub node */
+ {
+ char unit[1024];
+ full_name_of_hw (hw_parent (leaf), buf, sizeof_buf);
+ if (hw_unit_encode (hw_parent (leaf),
+ hw_unit_address (leaf),
+ unit + 1,
+ sizeof (unit) - 1)
+ > 0)
+ unit[0] = '@';
+ else
+ unit[0] = '\0';
+ if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit)
+ >= sizeof_buf)
+ hw_abort (leaf, "buffer overflow");
+ strcat (buf, "/");
+ strcat (buf, hw_name (leaf));
+ strcat (buf, unit);
+ }
+
+ /* return it usefully */
+ if (buf == full_name)
+ buf = (char *) strdup (full_name);
+ return buf;
+}
+
+struct hw *
+hw_create (SIM_DESC sd,
+ struct hw *parent,
+ const char *family,
+ const char *name,
+ const char *unit,
+ const char *args)
+{
+ struct hw *hw = ZALLOC (struct hw);
+
+ /* our identity */
+ hw->family_of_hw = family;
+ hw->name_of_hw = name;
+ hw->args_of_hw = args;
+
+ /* a hook into the system */
+ if (sd != NULL)
+ hw->system_of_hw = sd;
+ else if (parent != NULL)
+ hw->system_of_hw = hw_system (parent);
+ else
+ hw_abort (parent, "No system found");
+
+ /* in a tree */
+ if (parent != NULL)
+ {
+ struct hw **sibling = &parent->child_of_hw;
+ while ((*sibling) != NULL)
+ sibling = &(*sibling)->sibling_of_hw;
+ *sibling = hw;
+ hw->parent_of_hw = parent;
+ }
+
+ /* top of tree */
+ if (parent != NULL)
+ {
+ struct hw *root = parent;
+ while (root->parent_of_hw != NULL)
+ root = root->parent_of_hw;
+ hw->root_of_hw = root;
+ }
+
+ /* a unique identifier for the device on the parents bus */
+ if (parent != NULL)
+ {
+ hw_unit_decode (parent, unit, &hw->unit_address_of_hw);
+ }
+
+ /* Determine our path */
+ if (parent != NULL)
+ hw->path_of_hw = full_name_of_hw (hw, NULL, 0);
+ else
+ hw->path_of_hw = "/";
+
+ /* our callbacks */
+ set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
+ set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
+ set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer);
+ set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer);
+ set_hw_unit_decode (hw, generic_hw_unit_decode);
+ set_hw_unit_encode (hw, generic_hw_unit_encode);
+ set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address);
+ set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
+ set_hw_attach_address (hw, passthrough_hw_attach_address);
+ set_hw_detach_address (hw, passthrough_hw_detach_address);
+
+ /* locate a descriptor */
+ {
+ const struct hw_device_descriptor **table;
+ for (table = hw_descriptors;
+ *table != NULL;
+ table++)
+ {
+ const struct hw_device_descriptor *entry;
+ for (entry = *table;
+ entry->family != NULL;
+ entry++)
+ {
+ if (strcmp (family, entry->family) == 0)
+ {
+ hw->base_of_hw = ZALLOC (struct hw_base_data);
+ hw->base_of_hw->descriptor = entry;
+ hw->base_of_hw->finished_p = 0;
+ }
+ }
+ }
+ if (hw->base_of_hw == NULL)
+ {
+ hw_abort (parent, "Unknown device `%s'", family);
+ }
+ }
+
+ /* Attach dummy ports */
+ set_hw_ports (hw, empty_hw_ports);
+ set_hw_port_event (hw, panic_hw_port_event);
+
+ return hw;
+}
+
+
+int
+hw_finished_p (struct hw *me)
+{
+ return (me->base_of_hw->finished_p);
+}
+
+void
+hw_finish (struct hw *me)
+{
+ if (hw_finished_p (me))
+ hw_abort (me, "Attempt to finish finished device");
+
+ /* Fill in the (hopefully) defined address/size cells values */
+ if (hw_find_property (me, "#address-cells") != NULL)
+ me->nr_address_cells_of_hw_unit =
+ hw_find_integer_property (me, "#address-cells");
+ else
+ me->nr_address_cells_of_hw_unit = 2;
+ if (hw_find_property (me, "#size-cells") != NULL)
+ me->nr_size_cells_of_hw_unit =
+ hw_find_integer_property (me, "#size-cells");
+ else
+ me->nr_size_cells_of_hw_unit = 1;
+
+ /* Allow the real device to override any methods */
+ me->base_of_hw->descriptor->to_finish (me);
+ me->base_of_hw->finished_p = 1;
+}
diff --git a/sim/common/hw-device.h b/sim/common/hw-device.h
new file mode 100644
index 0000000..ecbedca
--- /dev/null
+++ b/sim/common/hw-device.h
@@ -0,0 +1,496 @@
+/* This file is part of the program psim.
+
+ Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
+
+ 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 of the License, 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_DEVICE_H
+#define HW_DEVICE_H
+
+/* declared in sim-basics.h, this object is used everywhere */
+/* typedef struct _device device; */
+
+
+/* Introduction:
+
+ As explained in earlier sections, the device, device instance,
+ property and ports lie at the heart of PSIM's device model.
+
+ In the below a synopsis of the device object and the operations it
+ supports are given.
+ */
+
+
+/* Creation:
+
+ The devices are created using a sequence of steps. In particular:
+
+ o A tree framework is created.
+
+ At this point, properties can be modified and extra
+ devices inserted (or removed?).
+
+#if LATER
+
+ Any properties that have a run-time value (eg ihandle
+ or device instance pointer properties) are entered
+ into the device tree using a named reference to the
+ corresponding runtime object that is to be created.
+
+#endif
+
+ o Real devices are created for all the dummy devices.
+
+ A device can assume that all of its parents have been
+ initialized.
+
+ A device can assume that all non run-time properties
+ have been initialized.
+
+ As part of being created, the device normally attaches
+ itself to its parent bus.
+
+#if LATER
+
+ Device instance data is initialized.
+
+#endif
+
+#if LATER
+
+ o Any run-time properties are created.
+
+#endif
+
+#if MUCH_MUCH_LATER
+
+ o Some devices, as part of their initialization
+ might want to refer to ihandle properties
+ in the device tree.
+
+#endif
+
+ NOTES:
+
+ o It is important to separate the creation
+ of an actual device from the creation
+ of the tree. The alternative creating
+ the device in two stages: As a separate
+ entity and then as a part of the tree.
+
+#if LATER
+ o Run-time properties can not be created
+ until after the devices in the tree
+ have been created. Hence an extra pass
+ for handling them.
+#endif
+
+ */
+
+/* Relationships:
+
+ A device is able to determine its relationship to other devices
+ within the tree. Operations include querying for a devices parent,
+ sibling, child, name, and path (from the root).
+
+ */
+
+
+#define hw_parent(hw) ((hw)->parent_of_hw + 0)
+
+#define hw_sibling(hw) ((hw)->sibling_of_hw + 0)
+
+#define hw_child(hw) ((hw)->child_of_hw + 0)
+
+
+
+/* Herritage:
+
+ */
+
+#define hw_family(hw) ((hw)->family_of_hw + 0)
+
+#define hw_name(hw) ((hw)->name_of_hw + 0)
+
+#define hw_args(hw) ((hw)->args_of_hw + 0)
+
+#define hw_path(hw) ((hw)->path_of_hw + 0)
+
+
+
+/* Short cut to the root node of the tree */
+
+#define hw_root(hw) ((hw)->root_of_hw + 0)
+
+/* Short cut back to the simulator object */
+
+#define hw_system(hw) ((hw)->system_of_hw + 0)
+
+/* Device private data */
+
+#define hw_data(hw) ((hw)->data_of_hw)
+
+
+
+/* Perform a soft reset of the device */
+
+typedef unsigned (hw_reset_callback)
+ (struct hw *me);
+
+#define hw_reset(hw) ((hw)->to_reset (hw))
+
+
+/* Hardware operations:
+
+ Connecting a parent to its children is a common bus. The parent
+ node is described as the bus owner and is responisble for
+ co-ordinating bus operations. On the bus, a SPACE:ADDR pair is used
+ to specify an address. A device that is both a bus owner (parent)
+ and bus client (child) are refered to as a bridging device.
+
+ A child performing a data (DMA) transfer will pass its request to
+ the bus owner (the devices parent). The bus owner will then either
+ reflect the request to one of the other devices attached to the bus
+ (a child of the bus owner) or bridge the request up the tree to the
+ next bus. */
+
+
+/* Children attached to a bus can register (attach) themselves to
+ specific addresses on their attached bus.
+
+ (A device may also be implicitly attached to certain bus
+ addresses).
+
+ The SPACE:ADDR pair specify an address on the common bus that
+ connects the parent and child devices. */
+
+typedef void (hw_attach_address_callback)
+ (struct hw *me,
+ int level,
+ int space,
+ address_word addr,
+ address_word nr_bytes,
+ struct hw *client); /*callback/default*/
+
+#define hw_attach_address(me, level, space, addr, nr_bytes, client) \
+((me)->to_attach_address (me, level, space, addr, nr_bytes, client))
+
+
+typedef void (hw_detach_address_callback)
+ (struct hw *me,
+ int level,
+ int space,
+ address_word addr,
+ address_word nr_bytes,
+ struct hw *client); /*callback/default*/
+
+#define hw_detach_address(me, level, space, addr, nr_bytes, client) \
+((me)->to_detach_address (me, level, space, addr, nr_bytes, client))
+
+
+/* An IO operation from a parent to a child via the conecting bus.
+
+ The SPACE:ADDR pair specify an address on the bus shared between
+ the parent and child devices. */
+
+typedef unsigned (hw_io_read_buffer_callback)
+ (struct hw *me,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ sim_cpu *processor,
+ sim_cia cia);
+
+#define hw_io_read_buffer(hw, dest, space, addr, nr_bytes, processor, cia) \
+((hw)->to_io_read_buffer (hw, dest, space, addr, nr_bytes, processor, cia))
+
+typedef unsigned (hw_io_write_buffer_callback)
+ (struct hw *me,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ sim_cpu *processor,
+ sim_cia cia);
+
+#define hw_io_write_buffer(hw, src, space, addr, nr_bytes, processor, cia) \
+((hw)->to_io_write_buffer (hw, src, space, addr, nr_bytes, processor, cia))
+
+
+
+/* Conversly, the device pci1000,1@1 may need to perform a dma transfer
+ into the cpu/memory core. Just as I/O moves towards the leaves,
+ dma transfers move towards the core via the initiating devices
+ parent nodes. The root device (special) converts the DMA transfer
+ into reads/writes to memory.
+
+ The SPACE:ADDR pair specify an address on the common bus connecting
+ the parent and child devices. */
+
+typedef unsigned (hw_dma_read_buffer_callback)
+ (struct hw *bus,
+ void *dest,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes);
+
+#define hw_dma_read_buffer(bus, dest, space, addr, nr_bytes) \
+((bus)->to_dma_read_buffer (bus, dest, space, addr, nr_bytes))
+
+typedef unsigned (hw_dma_write_buffer_callback)
+ (struct hw *bus,
+ const void *source,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section);
+
+#define hw_dma_write_buffer(bus, src, space, addr, nr_bytes, violate_ro) \
+((bus)->to_dma_write_buffer (bus, src, space, addr, nr_bytes, violate_ro))
+
+/* Address/size specs for devices are encoded following a convention
+ similar to that used by OpenFirmware. In particular, an
+ address/size is packed into a sequence of up to four cell words.
+ The number of words determined by the number of {address,size}
+ cells attributes of the device. */
+
+typedef struct _hw_unit {
+ int nr_cells;
+ unsigned_cell cells[4]; /* unused cells are zero */
+} hw_unit;
+
+
+/* For the given bus, the number of address and size cells used in a
+ hw_unit. */
+
+#define hw_unit_nr_address_cells(bus) ((bus)->nr_address_cells_of_hw_unit + 0)
+
+#define hw_unit_nr_size_cells(bus) ((bus)->nr_size_cells_of_hw_unit + 0)
+
+
+/* For the given device, its identifying hw_unit address.
+
+ Each device has an identifying hw_unit address. That address is
+ used when identifying one of a number of identical devices on a
+ common controller bus. ex fd0&fd1. */
+
+const hw_unit *hw_unit_address
+(struct hw *me);
+
+
+/* Convert between a textual and the internal representation of a
+ hw_unit address/size.
+
+ NOTE: A device asks its parent to translate between a hw_unit and
+ textual representation. This is because the textual address of a
+ device is specified using the parent busses notation. */
+
+typedef int (hw_unit_decode_callback)
+ (struct hw *bus,
+ const char *encoded,
+ hw_unit *unit);
+
+#define hw_unit_decode(bus, encoded, unit) \
+((bus)->to_unit_decode (bus, encoded, unit))
+
+
+typedef int (hw_unit_encode_callback)
+ (struct hw *bus,
+ const hw_unit *unit,
+ char *encoded,
+ int sizeof_buf);
+
+#define hw_unit_encode(bus, unit, encoded, sizeof_encoded) \
+((bus)->to_unit_encode (bus, unit, encoded, sizeof_encoded))
+
+
+
+/* As the bus that the device is attached too, to translate a devices
+ hw_unit address/size into a form suitable for an attach address
+ call.
+
+ Return a zero result if the address should be ignored when looking
+ for attach addresses. */
+
+typedef int (hw_unit_address_to_attach_address_callback)
+ (struct hw *bus,
+ const hw_unit *unit_addr,
+ int *attach_space,
+ unsigned_word *attach_addr,
+ struct hw *client);
+
+#define hw_unit_address_to_attach_address(bus, unit_addr, attach_space, attach_addr, client) \
+((bus)->to_unit_address_to_attach_address (bus, unit_addr, attach_space, attach_addr, client))
+
+
+typedef int (hw_unit_size_to_attach_size_callback)
+ (struct hw *bus,
+ const hw_unit *unit_size,
+ unsigned *attach_size,
+ struct hw *client);
+
+#define hw_unit_size_to_attach_size(bus, unit_size, attach_size, client) \
+((bus)->to_unit_size_to_attach_size (bus, unit_size, attach_size, client))
+
+
+
+/* Utilities:
+
+ */
+
+/* IOCTL::
+
+ Often devices require `out of band' operations to be performed.
+ For instance a pal device may need to notify a PCI bridge device
+ that an interrupt ack cycle needs to be performed on the PCI bus.
+ Within PSIM such operations are performed by using the generic
+ ioctl call <<hw_ioctl()>>.
+
+ */
+
+typedef enum {
+ hw_ioctl_break, /* unsigned_word requested_break */
+ hw_ioctl_set_trace, /* void */
+ hw_ioctl_create_stack, /* unsigned_word *sp, char **argv, char **envp */
+ hw_ioctl_change_media, /* const char *new_image (possibly NULL) */
+ nr_hw_ioctl_requests,
+} hw_ioctl_request;
+
+typedef int (hw_ioctl_callback)
+ (struct hw *me,
+ sim_cpu *processor,
+ sim_cia cia,
+ hw_ioctl_request request,
+ va_list ap);
+
+int hw_ioctl
+(struct hw *me,
+ sim_cpu *processor,
+ sim_cia cia,
+ hw_ioctl_request request,
+ ...);
+
+
+/* Event queue:
+
+ Device specific versions of certain event handlers */
+
+typedef struct _hw_event hw_event;
+typedef void (hw_event_handler) (struct hw *me, void *data);
+
+hw_event *hw_event_queue_schedule
+(struct hw *me,
+ signed64 delta_time,
+ hw_event_handler *handler,
+ void *data);
+
+void hw_event_queue_deschedule
+(struct hw *me,
+ hw_event *event_to_remove);
+
+signed64 hw_event_queue_time
+(struct hw *me);
+
+
+
+/* Error reporting::
+
+ So that errors originating from devices appear in a consistent
+ format, the <<hw_abort()>> function can be used. Formats and
+ outputs the error message before aborting the simulation
+
+ Devices should use this function to abort the simulation except
+ when the abort reason leaves the simulation in a hazardous
+ condition (for instance a failed malloc).
+
+ */
+
+void volatile NORETURN hw_abort
+(struct hw *me,
+ const char *fmt,
+ ...) __attribute__ ((format (printf, 2, 3)));
+
+#define hw_trace_p(hw) ((hw)->trace_of_hw_p + 0)
+
+
+
+/* Some of the related functions require specific types */
+
+struct hw_property_data;
+struct hw_port_data;
+struct hw_base_data;
+
+/* Finally the hardware device - keep your grubby little mits off of
+ these internals! :-) */
+
+struct hw {
+
+ /* our relatives */
+ struct hw *parent_of_hw;
+ struct hw *sibling_of_hw;
+ struct hw *child_of_hw;
+
+ /* our identity */
+ const char *name_of_hw;
+ const char *family_of_hw;
+ const char *args_of_hw;
+ const char *path_of_hw;
+
+ /* our data */
+ void *data_of_hw;
+
+ /* hot links */
+ struct hw *root_of_hw;
+ SIM_DESC system_of_hw;
+
+ /* identifying data */
+ hw_unit unit_address_of_hw;
+ int nr_address_cells_of_hw_unit;
+ int nr_size_cells_of_hw_unit;
+
+ /* Soft reset */
+ hw_reset_callback *to_reset;
+
+ /* Basic callbacks */
+ hw_io_read_buffer_callback *to_io_read_buffer;
+ hw_io_write_buffer_callback *to_io_write_buffer;
+ hw_dma_read_buffer_callback *to_dma_read_buffer;
+ hw_dma_write_buffer_callback *to_dma_write_buffer;
+ hw_attach_address_callback *to_attach_address;
+ hw_detach_address_callback *to_detach_address;
+
+ /* More complicated callbacks */
+ hw_ioctl_callback *to_ioctl;
+ int trace_of_hw_p;
+
+ /* address callbacks */
+ hw_unit_decode_callback *to_unit_decode;
+ hw_unit_encode_callback *to_unit_encode;
+ hw_unit_address_to_attach_address_callback *to_unit_address_to_attach_address;
+ hw_unit_size_to_attach_size_callback *to_unit_size_to_attach_size;
+
+ /* related data */
+ struct hw_property_data *properties_of_hw;
+ struct hw_port_data *ports_of_hw;
+ struct hw_base_data *base_of_hw;
+
+};
+
+
+#endif