diff options
Diffstat (limited to 'sim/ppc/device.maybe')
-rw-r--r-- | sim/ppc/device.maybe | 876 |
1 files changed, 876 insertions, 0 deletions
diff --git a/sim/ppc/device.maybe b/sim/ppc/device.maybe new file mode 100644 index 0000000..b18ade1 --- /dev/null +++ b/sim/ppc/device.maybe @@ -0,0 +1,876 @@ +/* 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. + + */ + + +#ifndef _DEVICE_H_ +#define _DEVICE_H_ + +#ifndef INLINE_DEVICE +#define INLINE_DEVICE +#endif + +/* declared in basics.h, this object is used everywhere */ +/* typedef struct _device device; */ + + +/* Device templates: + + *** THIS SECTION DESCRIBES HOW A DEVICE HAS A STATIC AND DYNAMIC + COMPONENT ** on the device in the tree is dynamic. ***** + + A device node is created from its template. The only valid + operation on a template is to create a device node from it: */ + +INLINE_DEVICE\ +(device *) device_template_create_device +(device *parent, + const char *name, + const char *unit_address, + const char *args); + +/* The create is paramaterized by both the devices unit address (a + string that is converted into numeric form by the devices parent) + and optionally extra argument information. + + The actual device node is constructed by a number of pieces provided + by the template function: */ + +typedef struct _device_callbacks device_callbacks; + +INLINE_DEVICE\ +(device *) device_create_from +(const char *name, + const device_unit *unit_address, + void *data, + const device_callbacks *callbacks, + device *parent); + +/* OpenBoot discusses the creation of packages (devices). */ + + +/* Devices: + + As with OpenBoot, all nodes in the device tree are considered to be + devices. Each node then has associated with it a number of methods + and properties (duscussed later). + + OpenBoot documentation refers to devices, device nodes, packages, + package instances, methods, static methods and properties. This + device implementation uses its own termonology. Where ever it + exists, the notes will indicate a correspondance between PSIM terms + and those found in OpenBoot. + + device: + + A device is the basic building block in this model. A device can + be further categorized into one of three classes - template, node + and instance. + + device-node (aka device): + + The device tree is constructed from device-nodes. Each node has + both local state (data), a relationship with the device nodes + around it and an address (unit-address) on the parents bus `bus' */ + +INLINE_DEVICE\ +(device *) device_parent +(device *me); + +INLINE_DEVICE\ +(device *) device_sibling +(device *me); + +INLINE_DEVICE\ +(device *) device_child +(device *me); + +INLINE_DEVICE\ +(const char *) device_name +(device *me); + +INLINE_DEVICE\ +(const char *) device_path +(device *me); + +INLINE_DEVICE\ +(void *) device_data +(device *me); + +INLINE_DEVICE\ +(psim *) device_system +(device *me); + +typedef struct _device_unit { + int nr_cells; + unsigned32 cells[4]; /* unused cells are zero */ +} device_unit; + +INLINE_DEVICE\ +(const device_unit *) device_unit_address +(device *me); + +/* Each device-node normally corresponds to a hardware component of + the system being modeled. Leaf nodes matching external devices and + intermediate nodes matching bridges and controllers. + + Device nodes also support methods that are an abstraction of the + transactions that occure in real hardware. These operations + (io/dma read/writes and interrupts) are discussed separatly. + + OpenBoot refers to device nodes by many names. The most common are + device, device node and package. */ + + +/* Properties: + + In IEEE1275 many of the the characteristics of a device are stored + in the device tree as properties. Each property consists of a name + and an associated (implicitly typed) value. A device will have a + list of properties attached to it. The user is able to manipulate + the list, adding and removing properties and set/modify the value + of each property. + + PSIM's device tree follows this model but with the addition of + strongly typing each property's value. The simulator will detect + at run time, the incorrect use of a property. + + In addition to the standard use of properties, Both PSIM and + individual devices will use properties to record simulation + configuration information. For instance, a disk device might store + in a string property called <<file>> the name of the file that + contains the disk image to use. */ + +/* The following are valid property types. The property `array' is a + for generic untyped data. */ + +typedef enum { + array_property, + boolean_property, + ihandle_property, + integer_property, + string_property, +} device_property_type; + +typedef struct _device_property device_property; +struct _device_property { + device *owner; + const char *name; + device_property_type type; + unsigned sizeof_array; + const void *array; + const device_property *original; + object_disposition disposition; +}; + + +/* iterate through the properties attached to a device */ + +INLINE_DEVICE\ +(const device_property *) device_next_property +(const device_property *previous); + +INLINE_DEVICE\ +(const device_property *) device_find_property +(device *me, + const char *property); /* NULL for first property */ + + +/* Manipulate the properties belonging to a given device. + + SET on the other hand will force the properties value. The + simulation is aborted if the property was present but of a + conflicting type. + + FIND returns the specified properties value, aborting the + simulation if the property is missing. Code locating a property + should first check its type (using device_find_property above) and + then obtain its value using the below. */ + + +INLINE_DEVICE\ +(void) device_set_array_property +(device *me, + const char *property, + const void *array, + int sizeof_array); + +INLINE_DEVICE\ +(const device_property *) device_find_array_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_boolean_property +(device *me, + const char *property, + int bool); +#endif + +INLINE_DEVICE\ +(int) device_find_boolean_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_ihandle_property +(device *me, + const char *property, + device_instance *ihandle); +#endif + +INLINE_DEVICE\ +(device_instance *) device_find_ihandle_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_integer_property +(device *me, + const char *property, + signed_word integer); +#endif + +INLINE_DEVICE\ +(signed_word) device_find_integer_property +(device *me, + const char *property); + + +#if 0 +INLINE_DEVICE\ +(void) device_set_string_property +(device *me, + const char *property, + const char *string); +#endif + +INLINE_DEVICE\ +(const char *) device_find_string_property +(device *me, + const char *property); + + +/* Instances: + + As with IEEE1275, a device can be opened, creating an instance. + Instances provide more abstract interfaces to the underlying + hardware. For example, the instance methods for a disk may include + code that is able to interpret file systems found on disks. Such + methods would there for allow the manipulation of files on the + disks file system. The operations would be implemented using the + basic block I/O model provided by the disk. + + This model includes methods that faciliate the creation of device + instance and (should a given device support it) standard operations + on those instances. */ + + *** device-instance *** + + Devices support an abstract I/O model. A unique I/O instance can be + created from a device node and then this instance used to perform + I/O that is independant of other instances. */ + +typedef struct _device_instance_callbacks device_instance_callbacks; + +INLINE_DEVICE\ +(device_instance *) device_create_instance_from +(device *me, /*OR*/ device_instance *parent, + void *data, + const char *path, + const char *args, + const device_instance_callbacks *callbacks); + +INLINE_DEVICE\ +(device_instance *) device_create_instance +(device *me, + const char *device_specifier); + +INLINE_DEVICE\ +(void) device_instance_delete +(device_instance *instance); + +INLINE_DEVICE\ +(int) device_instance_read +(device_instance *instance, + void *addr, + unsigned_word len); + +INLINE_DEVICE\ +(int) device_instance_write +(device_instance *instance, + const void *addr, + unsigned_word len); + +INLINE_DEVICE\ +(int) device_instance_seek +(device_instance *instance, + unsigned_word pos_hi, + unsigned_word pos_lo); + +INLINE_DEVICE\ +(unsigned_word) device_instance_claim +(device_instance *instance, + unsigned_word address, + unsigned_word length, + unsigned_word alignment); + +INLINE_DEVICE\ +(void) device_instance_release +(device_instance *instance, + unsigned_word address, + unsigned_word length); + +INLINE_DEVICE\ +(device *) device_instance_device +(device_instance *instance); + +INLINE_DEVICE\ +(const char *) device_instance_path +(device_instance *instance); + +INLINE_DEVICE\ +(void *) device_instance_data +(device_instance *instance); + +/* A device instance can be marked (when created) as being permenant. + Such instances are assigned a reserved address and are *not* + deleted between simulation runs. + + OpenBoot refers to a device instace as a package instance */ + + +/* PIO: + + *** DESCRIBE HERE WHAT A PIO OPERATION IS and how, broadly it is + modeled **** + + + During initialization, each device attaches its self to is parent + registering the address spaces that it is interested in: + + a. The <<com>> device attaches its self to its parent <<phb>> + device at address <<0x3f8>> through to address <<0x3f8 + 16>>. + + b. The <<phb>> has in turn attached its self to addresses + <<0xf0000000 .. 0xf0100000>>. + + During the execution of the simulation propper, the following then + occure: + + 1. After any virtual to physical translation, the processor + passes the address to be read (or written to the core device). + (eg address 0xf00003f8). + + 2. The core device then looks up the specified addresses in its + address to device map, determines that in this case the address + belongs to the phb and passes it down. + + 3. The <<phb>> in turn determines that the address belongs to the + serial port and passes to that device the request for an access + to location <<0x3f8>>. + + @figure mio + + */ + +/* Device Hardware + + This model assumes that the data paths of the system being modeled + have a tree topology. That is, one or more processors sit at the + top of a tree. That tree containing leaf nodes (real devices) and + branch nodes (bridges). + + For instance, consider the tree: + + /pci # PCI-HOST bridge + /pci/pci1000,1@1 # A pci controller + /pci/isa8086 # PCI-ISA bridge + /pci/isa8086/fdc@300 # floppy disk controller on ISA bus + + A processor needing to access the device fdc@300 on the ISA bus + would do so using a data path that goes through the pci-host bridge + (pci)and the isa-pci bridge (isa8086) to finally reach the device + fdc@300. As the data transfer passes through each intermediate + bridging node that bridge device is able to (just like with real + hardware) manipulate either the address or data involved in the + transfer. */ + +INLINE_DEVICE\ +(unsigned) device_io_read_buffer +(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +INLINE_DEVICE\ +(unsigned) device_io_write_buffer +(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +/* To avoid the need for an intermediate (bridging) node to ask each + of its child devices in turn if an IO access is intended for them, + parent nodes maintain a table mapping addresses directly to + specific devices. When a device is `connected' to its bus it + attaches its self to its parent. */ + +/* Address access attributes */ +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_raw_memory, + attach_callback, + /* ... */ +} attach_type; + +INLINE_DEVICE\ +(void) device_attach_address +(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who); /*callback/default*/ + +INLINE_DEVICE\ +(void) device_detach_address +(device *me, + const char *name, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *who); /*callback/default*/ + +/* where the attached address space can be any of + + callback - all accesses to that range of addresses are past on to + the attached child device. The callback addresses are ordered + according to the callback level (attach_callback, .. + 1, .. + 2, + ...). Lower levels are searched first. This facilitates the + implementation of more unusual addressing schema such as + subtractive decoding (as seen on the PCI bus). Within a given + callback level addresses must not overlap. + + memory - the specified address space contains RAM, the node that is + having the ram attached is responsible for allocating space for and + maintaining that space. The device initiating the attach will not + be notified of accesses to such an attachement. + + The memory attachment is very important. By giving the parent node + the responsability (and freedom) of managing the RAM, that node is + able to implement memory spaces more efficiently. For instance it + could `cache' accesses or merge adjacent memory areas. + + + In addition to I/O and DMA, devices interact with the rest of the + system via interrupts. Interrupts are discussed separatly. */ + + +/* DMA: + + *** DESCRIBE HERE WHAT A DMA OPERATION IS AND HOW IT IS MODELED, + include an interation of an access being reflected back down *** + + */ + +/* Conversly, the device pci1000,1@1 my 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 */ + +INLINE_DEVICE\ +(unsigned) device_dma_read_buffer +(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes); + +INLINE_DEVICE\ +(unsigned) device_dma_write_buffer +(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section); + + +/* Interrupts: + + *** DESCRIBE HERE THE INTERRUPT NETWORK *** + + PSIM models interrupts and their wiring as a directed graph of + connections between interrupt sources and destinations. The source + and destination are both a tupple consisting of a port number and + device. Both multiple destinations attached to a single source and + multiple sources attached to a single destination are allowed. + + When a device drives an interrupt port with multiple destinations a + broadcast of that interrupt event (message to all destinations) + occures. Each of those destination (device/port) are able to + further propogate the interrupt until it reaches its ultimate + destination. + + Normally an interrupt source would be a model of a real device + (such as a keyboard) while an interrupt destination would be an + interrupt controller. The facility that allows an interrupt to be + delivered to multiple devices and to be propogated from device to + device was designed to support the requirements specified by + OpenPIC (ISA interrupts go to both OpenPIC and 8259), CHRP (8259 + connected to OpenPIC) and hardware designs such as PCI-PCI + bridges. */ + + +/* Interrupting a processor + + The cpu object provides methods for delivering external interrupts + to a given processor. + + The problem of synchronizing external interrupt delivery with the + execution of the cpu is handled internally by the processor object. */ + + + +/* Interrupt Source + + A device drives its interrupt line using the call: */ + +INLINE_DEVICE\ +(void) device_interrupt_event +(device *me, + int my_port, + int value, + cpu *processor, + unsigned_word cia); + +/* This interrupt event will then be propogated to any attached + interrupt destinations. + + Any interpretation of PORT and VALUE is model dependant. However + as guidelines the following are recommended: PCI interrupts a-d + correspond to lines 0-3; level sensative interrupts be requested + with a value of one and withdrawn with a value of 0; edge sensative + interrupts always have a value of 1, the event its self is treated + as the interrupt. + + + Interrupt Destinations + + Attached to each interrupt line of a device can be zero or more + desitinations. These destinations consist of a device/port pair. + A destination is attached/detached to a device line using the + attach and detach calls. */ + +INLINE_DEVICE\ +(void) device_interrupt_attach +(device *me, + int my_port, + device *dest, + int dest_port, + object_disposition disposition); + +INLINE_DEVICE\ +(void) device_interrupt_detach +(device *me, + int my_port, + device *dest, + int dest_port); + +/* DESTINATION is attached (detached) to LINE of the device ME + + + Interrupt conversion + + Users refer to interrupt port numbers symbolically. For instance a + device may refer to its `INT' signal which is internally + represented by port 3. + + To convert to/from the symbolic and internal representation of a + port name/number. The following functions are available. */ + +INLINE_DEVICE\ +(int) device_interrupt_decode +(device *me, + const char *symbolic_name); + +INLINE_DEVICE\ +(int) device_interrupt_encode +(device *me, + int port_number, + char *buf, + int sizeof_buf); + + + +/* Initialization: + + In PSIM, the device tree is created and then initialized in stages. + When using devices it is important to be clear what initialization + the simulator assumes is being performed during each of these + stages. + + Firstly, each device is created in isolation (using the create from + template method). Only after it has been created will a device be + inserted into the tree ready for initialization. + + Once the tree is created, it is initialized as follows: + + 1. All properties (apart from those containing instances) + are (re)initialized + + 2. Any interrupts addeded as part of the simulation run + are removed. + + 4. The initialize address method of each device (in top + down order) is called. At this stage the device + is expected to: + + o Clear address maps and delete allocated memory + associated with the devices children. + + o (Re)attach its own addresses to its parent device. + + o Ensure that it is otherwize sufficiently + initialized such that it is ready for a + device instance create call. + + 5. All properties containing an instance of + a device are (re)initialized + + 6. The initialize data method for each device is called (in + top down) order. At this stage the device is expected to: + + o Perform any needed data transfers. Such + transfers would include the initialization + of memory created during the address initialization + stage using DMA. + + */ + +INLINE_DEVICE\ +(void) device_tree_init +(device *root, + psim *system); + + + +/* 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. */ + +EXTERN_DEVICE\ +(int) device_ioctl +(device *me, + cpu *processor, + unsigned_word cia, + ...); + + +/* External communcation: + + Devices interface to the external environment */ + +/* device_error() reports the problem to the console and aborts the + simulation. The error message is prefixed with the name of the + reporting device. */ + +EXTERN_DEVICE\ +(void volatile) device_error +(device *me, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + + +/* Tree utilities: + + In addition to the standard method of creating a device from a + device template, the following sortcuts can be used. + + Create a device or property from a textual representation */ + +EXTERN_DEVICE\ +(device *) device_tree_add_parsed +(device *current, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +/* where FMT,... once formatted (using vsprintf) is used to locate and + create either a device or property. Its syntax is almost identical + to that used in OpenBoot documentation - the only extension is in + allowing properties and their values to be specified vis: + + "/pci/pci1000,1@1/disk@0,0" + + Path: + + The path to a device or property can either be absolute (leading + `/') or relative (leading `.' or `..'). Relative paths start from + the CURRENT node. The new current node is returned as the result. + In addition, a path may start with a leading alias (resolved by + looking in /aliases). + + Device name: + + <name> "@" <unit> [ ":" <args> ] + + Where <name> is the name of the template device, <unit> is a + textual specification of the devices unit address (that is + converted into a numeric form by the devices parent) and <args> are + optional additional information to be passed to the device-template + when it creates the device. + + Properties: + + Properties are specified in a similar way to devices except that + the last element on the path (which would have been the device) is + the property name. This path is then followed by the property + value. Unlike OpenBoot, the property values in the device tree are + strongly typed. + + String property: + + <property-name> " " <text> + <property-name> " " "\"" <text> + + Boolean property: + + <property-name> " " [ "true" | "false" ] + Integer property or integer array property: + + <property-name> " " <number> { <number> } + + Phandle property: + + <property-name> " " "&" <path-to-device> + + Ihandle property: + + <property-name> " " "*" <path-to-device-to-open> + + Duplicate existing property: + + <property-name> " " "!" <path-to-original-property> + + + In addition to properties, the wiring of interrupts can be + specified: + + Attach interrupt <line> of <device> to <controller>: + + <device> " " ">" <my-port> <dest-port> <dest-device> + + + Once created, a device tree can be traversed in various orders: */ + +typedef void (device_tree_traverse_function) + (device *device, + void *data); + +INLINE_DEVICE\ +(void) device_tree_traverse +(device *root, + device_tree_traverse_function *prefix, + device_tree_traverse_function *postfix, + void *data); + +/* Or dumped out in a format that can be read back in using + device_add_parsed() */ + +INLINE_DEVICE\ +(void) device_tree_print_device +(device *device, + void *ignore_data_argument); + +/* Individual nodes can be located using */ + +INLINE_DEVICE\ +(device *) device_tree_find_device +(device *root, + const char *path); + +/* And the current list of devices can be listed */ + +INLINE_DEVICE\ +(void) device_usage +(int verbose); + + +/* ihandles and phandles: + + Both device nodes and device instances, in OpenBoot firmware have + an external representation (phandles and ihandles) and these values + are both stored in the device tree in property nodes and passed + between the client program and the simulator during emulation + calls. + + To limit the potential risk associated with trusing `data' from the + client program, the following mapping operators `safely' convert + between the two representations: */ + +INLINE_DEVICE\ +(device *) external_to_device +(device *tree_member, + unsigned32 phandle); + +INLINE_DEVICE\ +(unsigned32) device_to_external +(device *me); + +INLINE_DEVICE\ +(device_instance *) external_to_device_instance +(device *tree_member, + unsigned32 ihandle); + +INLINE_DEVICE\ +(unsigned32) device_instance_to_external +(device_instance *me); + +#endif /* _DEVICE_H_ */ |