aboutsummaryrefslogtreecommitdiff
path: root/sim/ppc/devices.h
diff options
context:
space:
mode:
Diffstat (limited to 'sim/ppc/devices.h')
-rw-r--r--sim/ppc/devices.h308
1 files changed, 301 insertions, 7 deletions
diff --git a/sim/ppc/devices.h b/sim/ppc/devices.h
index e115779..681992e 100644
--- a/sim/ppc/devices.h
+++ b/sim/ppc/devices.h
@@ -26,17 +26,311 @@
#define INLINE_DEVICES
#endif
-#include "device_tree.h"
-/* table of all the configured devices */
+/* forward declaration of types */
+/* typedef struct _device device; -- in devices.h */
-typedef struct _device_descriptor device_descriptor;
-struct _device_descriptor {
- char *name;
- device_creator *creator;
+
+/* Address access attributes that can be attached to a devices address
+ range */
+typedef enum _access_type {
+ access_invalid = 0,
+ access_read = 1,
+ access_write = 2,
+ access_read_write = 3,
+ access_exec = 4,
+ access_read_exec = 5,
+ access_write_exec = 6,
+ access_read_write_exec = 7,
+} access_type;
+
+/* Address attachement types */
+typedef enum _attach_type {
+ attach_invalid,
+ attach_callback,
+ attach_default,
+ attach_raw_memory,
+} attach_type;
+
+
+/* Operators on devices: */
+
+
+/* Initialization:
+
+ A device is made fully functional in two stages.
+
+ 1. It is created. A device is created _before_ it is entered into
+ the device tree. During creation any permenant structures needed
+ by the device should be created/initialized.
+
+ 2. It is initialized. Before a simulation run, each device in the
+ device tree is initialized in prefix order. As part of this
+ initialization, a device should (re)attach its self to its parent
+ as needed.
+
+ */
+
+typedef void (device_init_callback)
+ (const device *me,
+ psim *system);
+
+
+/* Data transfers:
+
+ A device may permit the reading/writing (IO) of its registers in
+ one or more address spaces. For instance, a PCI device may have
+ config registers in its config space and control registers in both
+ the io and memory spaces of a PCI bus.
+
+ Similarly, a device may initiate a data transfer (DMA) by passing
+ such a request up to its parent.
+
+ Init:
+
+ As part of its initialization (not creation) and possibly also as a
+ consequence of IO a device may attach its self to one or more of
+ the address spaces of its parent device.
+
+ For instance, a PCI device, during initialization would attach its
+ config registers (space=0?, base=0, nr_bytes=64) to its parent PCI
+ bridge. Later, due to a write to this config space, the same
+ device may in turn find it necessary to also attach its self to
+ it's parent's `memory' or `io' space.
+
+ To perform these operations, a device will call upon its parent
+ using either device_attach_address or device_detach_address.
+
+ * Any address specified is according to what the device expects to
+ see.
+
+ * Any detach operation must exactly match a previous attach.
+
+ * included with the attach or detach is the devices name, the
+ parent may use this as part of determining how to map map between a
+ child's address + space and its own.
+
+ * at any time, at most one device can have a default mapping
+ registered.
+
+
+ IO:
+
+ A device receives requests to perform reads/writes to its registers
+ or memory either A. from a processor or B. from a parent device.
+
+ The device may then in turn either A. resolve the IO request
+ locally by processing the data or trigering an exception or
+ B. re-mapping the access onto one of its local address spaces and
+ then in turn passing that on to one of its children.
+
+ * Any address passed is relative to the local device. Eg for PCI
+ config registers, the address would (normally) be in the range of 0
+ to 63.
+
+ * Any exception situtation triggered by an IO operation (processor
+ != NULL) is handled in one of the following ways: 1. Machine check
+ (and similar): issued immediatly by restarting the cpu; 2. External
+ exception: issue delayed (using events.h) until the current
+ instruction execution cycle is completed; 3. Slave device (and
+ similar): the need for the interrupt is passed on to the devices
+ parent (which being an interrupt control unit will in turn take one
+ of the actions described here); 4. Forget it.
+
+ * Any exception situtation trigered by a non IO operation
+ (processor == NULL) is handled buy returning 0.
+
+ * Transfers of size <= 8 and of a power of 2 *must* be correctly
+ aligned and should be treated as a `single cycle' transfer.
+
+ DMA:
+
+ A device initiates a DMA transfer by calling its parent with the
+ request. At the top level (if not done earlier) this is reflected
+ back down the tree as io read/writes to the target device.
+
+ This function is subject to change ...
+
+ */
+
+typedef void (device_config_address_callback)
+ (const device *me,
+ const char *name,
+ attach_type type,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ access_type access,
+ const device *who); /*callback/default*/
+
+typedef unsigned (device_io_read_buffer_callback)
+ (const device *me,
+ void *dest,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia);
+
+typedef unsigned (device_io_write_buffer_callback)
+ (const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia);
+
+typedef unsigned (device_dma_read_buffer_callback)
+ (const device *me,
+ void *dest,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes);
+
+typedef unsigned (device_dma_write_buffer_callback)
+ (const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section);
+
+
+/* Interrupts:
+
+ As mentioned above. Instead of handling an interrupt directly, a
+ device may instead pass the need to interrupt on to its parent.
+
+ Init:
+
+ Before passing interrupts up to is parent, a device must first
+ attach its interrupt lines to the parent device. To do this, the
+ device uses the parents attach/detach calls.
+
+ Interrupts:
+
+ A child notifies a parent of a change in an interrupt lines status
+ using the interrupt call. Similarly, a parent may notify a child
+ of any `interrupt ack' sequence using the interrupt_ack call.
+
+ */
+
+typedef void (device_config_interrupt_callback)
+ (const device *me,
+ const device *who,
+ int interrupt_line,
+ const char *name);
+
+typedef void (device_interrupt_ack_callback)
+ (const device *me,
+ int interrupt_line,
+ int interrupt_status);
+
+typedef void (device_interrupt_callback)
+ (const device *me,
+ const device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia);
+
+
+/* IOCTL:
+
+ Very simply, a catch all for any thing that turns up that until now
+ either hasn't been thought of or doesn't justify an extra function. */
+
+
+typedef void (device_ioctl_callback)
+ (const device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ ...);
+
+
+
+/* the callbacks */
+
+typedef struct _device_callbacks {
+ /* initialization */
+ device_init_callback *init;
+ /* address/data config - from child */
+ device_config_address_callback *attach_address;
+ device_config_address_callback *detach_address;
+ /* address/data transfer - to child */
+ device_io_read_buffer_callback *io_read_buffer;
+ device_io_write_buffer_callback *io_write_buffer;
+ /* address/data transfer - from child */
+ device_dma_read_buffer_callback *dma_read_buffer;
+ device_dma_write_buffer_callback *dma_write_buffer;
+ /* interrupt config - from child */
+ device_config_interrupt_callback *attach_interrupt;
+ device_config_interrupt_callback *detach_interrupt;
+ /* interrupt transfer - from child */
+ device_interrupt_callback *interrupt;
+ /* interrupt transfer - to child */
+ device_interrupt_ack_callback *interrupt_ack;
+ /* back door to anything we've forgot */
+ device_ioctl_callback *ioctl;
+} device_callbacks;
+
+/* A device */
+struct _device {
+ const char *name; /* eg rom@0x1234, 0x400 */
+ void *data; /* device specific data */
+ const device_callbacks *callback;
+ const device *parent;
};
-INLINE_DEVICES device_descriptor *find_device_descriptor(char *name);
+/* Create a new device, finding it in the builtin device table */
+
+INLINE_DEVICES const device *device_create
+(const char *name,
+ const device *parent);
+
+/* create a new device using the parameterized data */
+
+INLINE_DEVICES const device *device_create_from
+(const char *name,
+ void *data,
+ const device_callbacks *callback,
+ const device *parent);
+
+
+/* Unimplemented call back functions. These abort the simulation */
+
+INLINE_DEVICES device_init_callback unimp_device_init;
+INLINE_DEVICES device_config_address_callback unimp_device_attach_address;
+INLINE_DEVICES device_config_address_callback unimp_device_detach_address;
+INLINE_DEVICES device_io_read_buffer_callback unimp_device_io_read_buffer;
+INLINE_DEVICES device_io_write_buffer_callback unimp_device_io_write_buffer;
+INLINE_DEVICES device_dma_read_buffer_callback unimp_device_dma_read_buffer;
+INLINE_DEVICES device_dma_write_buffer_callback unimp_device_dma_write_buffer;
+INLINE_DEVICES device_config_interrupt_callback unimp_device_attach_interrupt;
+INLINE_DEVICES device_config_interrupt_callback unimp_device_detach_interrupt;
+INLINE_DEVICES device_interrupt_callback unimp_device_interrupt;
+INLINE_DEVICES device_interrupt_ack_callback unimp_device_interrupt_ack;
+INLINE_DEVICES device_ioctl_callback unimp_device_ioctl;
+
+/* Pass through and ignore callback functions. A call going towards
+ the root device are passed on up, local calls are ignored and call
+ downs abort */
+
+INLINE_DEVICES device_init_callback ignore_device_init;
+INLINE_DEVICES device_config_address_callback pass_device_attach_address;
+INLINE_DEVICES device_config_address_callback pass_device_detach_address;
+INLINE_DEVICES device_dma_read_buffer_callback pass_device_dma_read_buffer;
+INLINE_DEVICES device_dma_write_buffer_callback pass_device_dma_write_buffer;
+INLINE_DEVICES device_config_interrupt_callback pass_device_attach_interrupt;
+INLINE_DEVICES device_config_interrupt_callback pass_device_detach_interrupt;
+INLINE_DEVICES device_interrupt_callback pass_device_interrupt;
+
+INLINE_DEVICES const device_callbacks *passthrough_device_callbacks
+(void);
+
+
#endif /* _DEVICES_H_ */