mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
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.
This commit is contained in:
parent
6cfaad4d88
commit
b1e9223cee
@ -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.
|
||||
|
116
sim/common/dv-core.c
Normal file
116
sim/common/dv-core.c
Normal file
@ -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 },
|
||||
};
|
387
sim/common/dv-pal.c
Normal file
387
sim/common/dv-pal.c
Normal file
@ -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 },
|
||||
};
|
467
sim/common/hw-base.c
Normal file
467
sim/common/hw-base.c
Normal file
@ -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;
|
||||
}
|
496
sim/common/hw-device.h
Normal file
496
sim/common/hw-device.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user