aboutsummaryrefslogtreecommitdiff
path: root/sim/ppc/device.maybe
diff options
context:
space:
mode:
Diffstat (limited to 'sim/ppc/device.maybe')
-rw-r--r--sim/ppc/device.maybe876
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_ */