diff options
Diffstat (limited to 'sim/ppc/devices.h')
-rw-r--r-- | sim/ppc/devices.h | 308 |
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_ */ |