udi_pio_trans_t(3udi)


PIO transaction descriptor

SYNOPSIS

#include <udi.h>

typedef const struct {

	udi_ubit8_t pio_op;

	udi_ubit8_t tran_size;

	udi_ubit16_t operand;

} udi_pio_trans_t;
 
/* Values for tran_size */
 
#define  UDI_PIO_1BYTE				0
 
#define  UDI_PIO_2BYTE				1
 
#define  UDI_PIO_4BYTE				2
 
#define  UDI_PIO_8BYTE				3
 
#define  UDI_PIO_16BYTE				4
 
#define  UDI_PIO_32BYTE				5
 
/* Values for register numbers in pio_op */
 
#define UDI_PIO_R0 0 #define UDI_PIO_R1 1 #define UDI_PIO_R2 2 #define UDI_PIO_R3 3 #define UDI_PIO_R4 4 #define UDI_PIO_R5 5 #define UDI_PIO_R6 6 #define UDI_PIO_R7 7
/* Values for addressing modes in pio_op */
 
#define UDI_PIO_DIRECT 0x00 #define UDI_PIO_SCRATCH 0x08 #define UDI_PIO_BUF 0x10 #define UDI_PIO_MEM 0x18
/* Values for Class A opcodes in pio_op */
 
#define UDI_PIO_IN 0x00 #define UDI_PIO_OUT 0x20 #define UDI_PIO_LOAD 0x40 #define UDI_PIO_STORE 0x60
/* Values for Class B opcodes in pio_op */
 
#define UDI_PIO_LOAD_IMM 0x80 #define UDI_PIO_CSKIP 0x88 #define UDI_PIO_IN_IND 0x90 #define UDI_PIO_OUT_IND 0x98 #define UDI_PIO_SHIFT_LEFT 0xA0 #define UDI_PIO_SHIFT_RIGHT 0xA8 #define UDI_PIO_AND 0xB0 #define UDI_PIO_AND_IMM 0xB8 #define UDI_PIO_OR 0xC0 #define UDI_PIO_OR_IMM 0xC8 #define UDI_PIO_XOR 0xD0 #define UDI_PIO_ADD 0xD8 #define UDI_PIO_ADD_IMM 0xE0 #define UDI_PIO_SUB 0xE8
/* Values for Class C opcodes in pio_op */
 
#define UDI_PIO_BRANCH 0xF0 #define UDI_PIO_LABEL 0xF1 #define UDI_PIO_REP_IN_IND 0xF2 #define UDI_PIO_REP_OUT_IND 0xF3 #define UDI_PIO_DELAY 0xF4 #define UDI_PIO_BARRIER 0xF5 #define UDI_PIO_SYNC 0xF6 #define UDI_PIO_SYNC_OUT 0xF7 #define UDI_PIO_DEBUG 0xF8 #define UDI_PIO_END 0xFE #define UDI_PIO_END_IMM 0xFF

 
/* Values for UDI_PIO_DEBUG operand */
 
#define UDI_PIO_TRACE_OPS_NONE 0 #define UDI_PIO_TRACE_OPS1 1 #define UDI_PIO_TRACE_OPS2 2 #define UDI_PIO_TRACE_OPS3 3 #define UDI_PIO_TRACE_REGS_NONE (0U<<2) #define UDI_PIO_TRACE_REGS1 (1U<<2) #define UDI_PIO_TRACE_REGS2 (2U<<2) #define UDI_PIO_TRACE_REGS3 (3U<<2) #define UDI_PIO_TRACE_DEV_NONE (0U<<4) #define UDI_PIO_TRACE_DEV1 (1U<<4) #define UDI_PIO_TRACE_DEV2 (2U<<4) #define UDI_PIO_TRACE_DEV3 (3U<<4)

MEMBERS pio_op is the type of operation to use for this transaction. pio_op encodes the type of transaction and the selection of source and destination operands.

tran_size is the power-of-2 size of a basic PIO transaction. The actual size is 2tran_size bytes. The tran_size value must be from 0 to 5, corresponding to a transaction size of 1 to 32 bytes (256 bits). The mnemonic constants UDI_PIO_1BYTE through UDI_PIO_32BYTE are available for use in setting tran_size.

operand is an operand value or address for the transaction. Its interpretation depends on the type of operation given by pio_op.

DESCRIPTION A PIO transaction descriptor (udi_pio_trans_t) describes in most cases a single PIO register/memory access transaction or an operation using a set of temporary registers. Multiple such transaction descriptors may be combined into a single list, called a trans list, to perform more complex sequences with a single call to udi_pio_trans. Advanced operations in the trans list allow for bit manipulations, repeat counts, serialization, and conditional branching. All PIO transactions are subject to the rules and procedural information listed on page 4-13.

Each element in the trans list array represents a basic transaction, and operates on a single transaction-sized piece of data. When transferring data to or from a device (for example, with UDI_PIO_IN or UDI_PIO_OUT), the entire transaction-size bytes will be transferred as a single atomic bus transaction if possible. See udi_pio_atomic_sizes for a description of how to determine the atomic sizes supported on a particular platform.

While simple transactions can be handled with simple operations, UDI supports a rich set of PIO operation types, so that even fairly sophisticated manipulation of device data can be performed with a single call to udi_pio_trans. To allow these operations to be efficiently expressed, udi_pio_trans uses an abstract register load/store model.

During execution of udi_pio_trans, the UDI environment maintains a set of 8 temporary "registers", numbered 0 through 7, each of which can hold one data item up to 32 bytes (256 bits) in size. Most PIO operations use one or more of these registers. If the size of a value loaded into a register (determined by tran_size) is less than 32 bytes, the "upper" (most-significant) bytes are treated as zero if the register value is subsequently used with a larger transaction size. If a register value is used in an operation with a smaller transaction size than when the register was last loaded, the upper bytes will be ignored. Arithmetic operations do not generate underflows or overflows, they simply wrap around; in other words, all arithmetic is modulo 2^((2^tran_size)*8).

In addition to using the temporary registers, some PIO operations allow access to permanent memory associated with one of the arguments to udi_pio_trans. These operations can access control block scratch space, udi_buf_t buffer contents, or driver memory. Values in permanent memory are stored in the driver's endianness, even for transaction sizes larger than native word sizes. These values will be either purely little endian or purely big endian. (See the definitions of big endian and little endian in Section 3.2.2, "Common Terms," on page 3-2 of the UDI Core Specification.)

PIO operations are divided into 3 classes, based on the type of operands used: Class A, Class B, and Class C operations.

Class A Operations: Class A operations can use register values or permanent memory values. The pio_op value for a class A operation selects a register number (0-7) as well as an addressing mode from the following table.
Table 4-1 PIO Addressing Modes
Mnemonic Value Description
UDI_PIO_DIRECT 0x00 Register contents are used directly
UDI_PIO_SCRATCH 0x08 Register holds 32-bit offset into scratch space
UDI_PIO_BUF 0x10 Register holds 32-bit offset into buffer data
UDI_PIO_MEM 0x18 Register holds 32-bit offset into memory block

To set pio_op for a Class A operation, the register number and exactly one of the addressing mode mnemonics must be added to the opcode mnemonic:

pio_op = operation_code + addressing_mode + register

The mnemonic constants UDI_PIO_R0 through UDI_PIO_R7 are available for use in selecting registers for all opcodes and operands that use register numbers.

Class A pio_op values are encoded with the following bit patterns: 000aarrr - 011aarrr, where aa selects the addressing mode according to Table 4-1 and rrr selects a register number.

Class B Operations: Class B operations can use register values but not permanent memory values. The pio_op value for a class B operation selects a register number (0-7), which is used as if the UDI_PIO_DIRECT addressing mode were specified.

To set pio_op for a Class B operation, the register number must be added to the opcode mnemonic:

pio_op = operation_code + register

Class B pio_op values are encoded with the following bit patterns: 10000rrr - 11101rrr, where rrr selects a register number to be used with that addressing mode.

Class C Operations: Class C operations use neither register values nor permanent memory values. The pio_op value for a class C operation consists only of the opcode:

pio_op = operation_code

Class C pio_op values are encoded with the following bit patterns: 11110000 - 11111111.

The following tables list the opcodes for each class and their encoded values, along with the corresponding operation definitions, including an indication of how the operand value is used in each case. In these tables, addr means the contents of the location referred to by the selected addressing mode and register, reg(operand) means a direct register value where the low-order 3 bits of operand are used to select the register number (unless otherwise specified, the remaining bits must be zero), PIO(operand) means a location on the PIO device where operand indicates the desired PIO offset, and reg means the selected register contents.
Table 4-2 Class A PIO Operation Codes
Operation Code Value Operation
UDI_PIO_IN 0x00 addr <- PIO(operand)
UDI_PIO_OUT 0x20 PIO(operand) <- addr
UDI_PIO_LOAD 0x40 reg(operand) <- addr
UDI_PIO_STORE 0x60 addr <- reg(operand)
Table 4-3 Class B PIO Operation Codes
Operation Code Value Operation
UDI_PIO_LOAD_IMM 0x80 reg <- operand (multi-part)
UDI_PIO_CSKIP 0x88 Conditional skip. The value in reg is compared with zero. The operand value selects a condiction code from Table 4-5 to determine the type of comparison. If the condition is TRUE, the following trans list element will be skipped.
UDI_PIO_IN_IND 0x90 reg <- PIO(reg(operand))
UDI_PIO_OUT_IND 0x98 PIO(reg(operand)) <- reg
UDI_PIO_SHIFT_LEFT 0xA0 reg <- reg << operand
UDI_PIO_SHIFT_RIGHT 0xA8 reg <- reg >> operand
UDI_PIO_AND 0xB0 reg <- reg & reg(operand)
UDI_PIO_AND_IMM 0xB8 reg <- reg & operand (zero-extended)
UDI_PIO_OR 0xC0 reg <- reg | reg(operand)
UDI_PIO_OR_IMM 0xC8 reg <- reg | operand (zero-extended)
UDI_PIO_XOR 0xD0 reg <- reg ^ reg(operand)
UDI_PIO_ADD 0xD8 reg <- reg + reg(operand)
UDI_PIO_ADD_IMM 0xE0 reg <- reg + operand (sign-extended)
UDI_PIO_SUB 0xE8 reg <- reg - reg(operand)
Table 4-4 Class C PIO Operation Codes
Operation Code Value Operation
UDI_PIO_BRANCH 0xF0 Unconditional branch to the UDI_PIO_LABEL with the same operand value. tran_size is unused and must be set to zero.
UDI_PIO_LABEL 0xF1 Destination of a UDI_PIO_BRANCH. tran_size is unused and must be set to zero.
UDI_PIO_REP_IN_IND 0xF2 Repeated indirect PIO input transactions. operand is encoded according to the UDI_PIO_REP_ARGS macro described below.
UDI_PIO_REP_OUT_IND 0xF3 Repeated indirect PIO output transactions. operand is encoded according to the UDI_PIO_REP_ARGS macro described below.
UDI_PIO_DELAY 0xF4 Delay for at least operand microseconds during a PIO wait loop.
UDI_PIO_BARRIER 0xF5 Place an ordering barrier between PIO transactions. tran_size is unused and must be set to zero. See below for details on the behavior of this operation and its use of operand.
UDI_PIO_SYNC 0xF6 Synchronize with respect to outstanding PIO transactions. See below for details on the behavior of this operation and its use of tran_size and operand.
UDI_PIO_SYNC_OUT 0xF7 Synchronize with respect to outstanding PIO output transactions. See below for details on the behavior of this operation and its use of tran_size and operand.
UDI_PIO_DEBUG 0xF8 Enable/disable debug tracing of PIO transactions.
UDI_PIO_END 0xFE Terminate processing.result_code <- reg(operand)tran_size must be <= UDI_PIO_2BYTE.
UDI_PIO_END_IMM 0xFF Terminate processing.result_code <- operandtran_size must be UDI_PIO_2BYTE.

Detailed description of Addressing Modes:

UDI_PIO_DIRECT - In this mode, the contents of the selected register, reg, are used for the addr value itself. In this case, addr is unaffected by any stride values from UDI_PIO_REP_IN_IND or UDI_PIO_REP_OUT_IND operations.

UDI_PIO_SCRATCH - In this mode, the contents of the selected register, reg, are used as an offset into the scratch space of the control block passed to udi_pio_trans. The scratch space data bytes starting at this offset and extending for the selected transaction size are used as the addr value. Only the low-order 32 bits of the register value are used; any higher order bits are ignored; smaller values previously loaded into the register are zero-extended to 32 bits. The offset must be a multiple of the transaction size.

UDI_PIO_BUF - In this mode, the contents of the selected register, reg, are used as an offset into the valid data area of the udi_buf_t buffer passed to udi_pio_trans. The buffer data bytes starting at this offset and extending for the selected transaction size are used as the addr value. Only the low-order 32 bits of the register value are used; any higher order bits are ignored; smaller values previously loaded into the register are zero-extended to 32 bits. The offset must be a multiple of the transaction size. All offsets accessed with UDI_PIO_BUF must be less than the buffer's buf_size value at the time udi_pio_trans was called.

UDI_PIO_MEM - In this mode, the contents of the selected register, reg, are used as an offset into the auxiliary memory block pointed to by the mem_ptr argument passed to udi_pio_trans. The memory block data bytes starting at this offset and extending for the selected transaction size are used as the addr value. Only the low-order 32 bits of the register value are used; any higher order bits are ignored; smaller values previously loaded into the register are zero-extended to 32 bits. The offset must be a multiple of the transaction size.

When PIO device registers/memory are used as the source (UDI_PIO_IN, UDI_PIO_IN_IND, or UDI_PIO_REP_IN_IND) or destination (UDI_PIO_OUT, UDI_PIO_OUT_IND, or UDI_PIO_REP_OUT_IND) of an operation, the specified PIO offset is interpreted relative to the register set and base offset specified through arguments to udi_pio_map and passed to udi_pio_trans via the pio_handle argument. UDI_PIO_IN and UDI_PIO_OUT only support PIO offsets up to 65535. UDI_PIO_IN_IND, UDI_PIO_OUT_IND, UDI_PIO_REP_IN_IND and UDI_PIO_REP_OUT_IND use a register value to provide the PIO offset, allowing for indirections and larger offsets; the 32 low-order bits of the register value are used for the PIO offset; any higher order bits are ignored; smaller values previously loaded into the register are zero extended to 32 bits.

UDI_PIO_LOAD_IMM:

The immediate load operation takes a value directly from the operand portion of a transaction descriptor and loads it into the selected temporary register. The transaction size for this operation must be at least 2 bytes.

If UDI_PIO_LOAD_IMM is used with a transaction size greater than 2 bytes, multiple trans list elements are used to hold all the bytes of the immediate value. Starting from the least significant 2 bytes, pairs of bytes are loaded from each successive operand value starting from the UDI_PIO_LOAD_IMM trans list entry, where each pair is listed as most-significant-byte followed by least-significant-byte. The subsequent trans list elements which contain the additional byte values must repeat the pio_op and tran_size values from the initial UDI_PIO_LOAD_IMM operation. Normal trans list execution resumes after the last such element.

Shift operations:

UDI_PIO_SHIFT_LEFT and UDI_PIO_SHIFT_RIGHT use the operand value as a shift count for shifting the entire transaction-size byte register value. The shift count must be from 1 to 32. Any bits shifted out of the low order transaction-size bytes will be discarded. All bits shifted in to the low order transaction-size bytes will be zero. Any previous more significant bytes shall effectively be zeroed.

Repeat operations:

A UDI_PIO_REP_IN_IND or UDI_PIO_REP_OUT_IND operation can be used to repeat a basic PIO transaction  up  to 232-1 times. The basic PIO transaction is like a UDI_PIO_IN_IND or UDI_PIO_OUT_IND, in that it performs a PIO transaction between a PIO offset indicated in one register and a permanent memory location addressed via another register. A third register holds the repeat count, which must be from zero to 232-1.

The operand value for a repeat operation holds a number of parameters, intialized via the UDI_PIO_REP_ARGS macro. See UDI_PIO_REP_ARGS for more details on repeat operations.

Branching operations:

UDI_PIO_BRANCH is an unconditional branch operation. The operand value is used to find the next trans list element to execute instead of continuing in order. The operand value is matched against UDI_PIO_LABEL trans list elements; execution continues after the UDI_PIO_LABEL with the same operand value as the UDI_PIO_BRANCH. It is illegal to have two UDI_PIO_LABEL elements with the same operand value in one trans list. It is illegal to have a UDI_PIO_BRANCH that does not have a corresponding UDI_PIO_LABEL.

It is illegal to specify a UDI_PIO_LABEL or UDI_PIO_BRANCH transaction with an operand value of zero.

If a UDI_PIO_LABEL operation is executed sequentially, it acts as a no-op.

Conditional operation:

UDI_PIO_CSKIP is a conditional skip operation. It compares a register value with zero and skips the following operation if the comparison meets the required conditions. The operand specifies the condition code, according to the following table:
Table 4-5 PIO Condition Codes
Mnemonic Value Condition Description
UDI_PIO_Z
0
reg == 0
UDI_PIO_NZ
1
reg != 0
UDI_PIO_NEG
2
reg < 0 [signed]
UDI_PIO_NNEG
3
reg >= 0 [signed]

Busy-wait operation:

A UDI_PIO_DELAY pauses execution of the trans list for a specified time. Transaction lists that loop waiting for device events (such as ready bits being set in status registers) must include a UDI_PIO_DELAY in the loop to avoid consuming excessive CPU resources. The operand value provides the desired delay time in microseconds. This is a hint to the environment, and must not be used to perform precise timings. The environment will pause the execution of the PIO trans list for at least the requested amount of time.

Synchronization operations:

The synchronization operations (UDI_PIO_BARRIER, UDI_PIO_SYNC and UDI_PIO_SYNC_OUT) do not actually transfer any new data. Instead, they make sure that any PIO transactions that have already been generated are made visible to the device before any subsequent PIO transactions to/from the same device register set become visible (thus acting as a "barrier"). These operations only affect accesses to the device or memory referenced by the PIO handle, not buffer or driver memory.

The operand value for UDI_PIO_BARRIER must be either 0 or UDI_PIO_OUT. If UDI_PIO_OUT, the barrier is only guaranteed to act with respect to device output transactions; this may be faster than a full barrier.

The UDI_PIO_SYNC and UDI_PIO_SYNC_OUT operations provide even stronger synchronization: they also wait for the affected transactions to reach the device. UDI_PIO_SYNC affects all PIO transactions; UDI_PIO_SYNC_OUT is only required to affect output transactions. operand and tran_size must be set to a PIO offset range of the device that causes no side effects if input from. On some platforms, PIO transactions can only be synchronized by performing an additional PIO input transaction. In such cases, the environment will read 2tran_size bytes from offset operand of the device (and discard the result).

Synchronization operations are not needed if UDI_PIO_STRICTORDER was specified in the PIO attributes for the PIO handle. With UDI_PIO_STRICTORDER, each basic transaction that accesses the PIO device is followed by an implicit UDI_PIO_SYNC.

Upon completion of a udi_pio_trans sequence, via execution of a UDI_PIO_END operation, an implicit UDI_PIO_BARRIER with operand of zero is performed.

Environment implementations may choose to impose stronger ordering and synchronization than required by the synchronization operations used, up to and including strict ordering.

Debugging Operation:

The UDI_PIO_DEBUG operation controls PIO debug tracing. This opcode will be seldom, if ever, used in production drivers and is to be used mostly while a driver is under development. As with the other debugging facilities in UDI like udi_debug_printf and udi_debug_break, an environment may choose to completely or partially ignore this opcode. Each UDI environment must document how the debugging output is made available to the developer.

Upon entry to a trans list, all debugging is disabled. UDI_PIO_DEBUG opcodes are interpreted like all other opcodes; they are synchronous with the execution of the trans list. Each UDI_PIO_DEBUG opcode will reset the debug level regardless of the current debug level; they are not cumulative.

The trans_size must be zero since no PIO-visible data is transferred by this opcode. The operand provides a bitmask to control the level of debugging. If no flags are specified, debugging is disabled.

For each field, tracing information is generated only if the current debug level in the trans list is greater than or equal to the debugging level of the environment. The output at various levels is explictly specified; it's an agreement between the trans list author and the user of the environment controlling the trace level.

Termination Operations:

Upon reaching a UDI_PIO_END_IMM, processing of the trans list is terminated and the result code (an arbitrary 16-bit code that is defined by the driver) in the udi_pio_trans_call_t callback is set to the low byte of the operand value.

Upon reaching a UDI_PIO_END, processing of the trans list terminates as in the UDI_PIO_END_IMM case, except that the operand specifies the register number whose contents are to be returned as the result code.

The last element of a PIO trans list must be either a UDI_PIO_END operation, a UDI_PIO_END_IMM operation, or a UDI_PIO_BRANCH.

REFERENCES udi_pio_map, udi_pio_trans, UDI_PIO_REP_ARGS, udi_buf_t, udi_mem_alloc


UDI Physical I/O Specification Contents