The IOTester® tool directly support use of the <iohw.h> header proposed in the Technical Report ISO/IEC TR 18037 from the C standardization committee.
The goal with <iohw.h> is to standardize basic I/O hardware addressing in order to make I/O driver source code portable
to all processor systems where the peripheral I/O hardware itself can be connected.
Typical peripheral I/O hardware could, for instance, be: display controller chips, communication chips, etc.
In short the <iohw.h> header defines a number of (macro) functions for doing basic RD, WR, AND, OR, XOR operations
on I/O registers in peripheral hardware. Memory buffers in peripheral I/O hardware are in this respect
considered to be arrays of I/O registers.
The standardization concept ensure that the I/O device programmer only "see" the peripheral I/O registers, their characteristics and functionality, during I/O driver development and test. The underlying target hardware platform and CPU type become "don't care".
The most basic <iohw.h> functions
// Functions for single I/O register access
void iowr( ioreg_designator, unsigned dat );
void ioor( ioreg_designator, unsigned dat );
void ioand( ioreg_designator, unsigned dat );
void ioxor( ioreg_designator, unsigned dat );
unsigned int iord( ioreg_designator );
// Functions for access of an element in a I/O register buffer.
void iowrbuf( ioreg_designator, ioindex_t idx, unsigned dat );
void ioorbuf( ioreg_designator, ioindex_t idx, unsigned dat );
void ioandbuf( ioreg_designator, ioindex_t idx, unsigned dat );
void ioxorbuf( ioreg_designator, ioindex_t idx, unsigned dat );
unsigned int iordbuf( ioreg_designator, ioindex_t idx );
A requirement for platform portability is that a symbolic I/O register name must be used for the ioreg_designator parameter.
The symbolic I/O register name must be a reference to a COMPLETE description of how the specific I/O register should be accessed in the given platform.
This method for writing I/O driver code is just an extension of prior art. Today it is common pratice that I/O registers are always referenced in the source code by use of a symbolic name.
The special is that a function syntax for I/O access is always used. This ensure that the actual access method for the given platform can be fully encapsulated in the I/O access function body.
In practice basic I/O register access may be done with anything from call of target specific access functions to use of simple pointer based access.
The exact syntax for the I/O register definition (the ioreg_designator definition) will of course be C compiler and platform specific.
However by isolating the I/O register definitions in a separate header file, then only the header with the I/O register definitions has
to be updated when moving the I/O driver source code between target processor platforms.
The I/O driver source code itself will be unchanged and fully portable.
Example:
/* The portable driver source code */
#include <iohw.h> // The standardized I/O register access functions
#include <ioregisters.h> // I/O register definitions used by I/O driver source code
// Output pixel color to display controller data stream as 3 bytes: Red,Green,Blue
void output_pixel( unsigned long color)
{
iowr( DISP_DATA, (color >> 16) & 0xff);
iowr( DISP_DATA, (color >> 8) & 0xff);
iowr( DISP_DATA, color & 0xff);
}
Links to:
IOTester tool description
Example 1: Start using IOTester I/O port pins - "Single chip mode"
Example 2: Enabling the External bus
Example 3: Using Internal Devices and External bus.
Example 4: Using Target Interrupt.
Example 5: Writing portable I/O driver source code with <iohw.h>
Example 6: <iohw.h> implementation methods and definition of I/O registers
Example 7: Swapping source code between PC and target platforms