Standardize the syntax for I/O access in C / C++ with Stimuli-Gateway functions

There are a lot of good reasons for standardizing the syntax for I/O and interrupt operations in C and C++. The Stimuli-Gateway (SG) functions provide such standardization with existing C/C++ compilers on the market.

The Stimuli-Gateway design method has been in practical use by European companies since 1993 and in that time has gradually evolved to the form it has today.

The SG I/O standardization method enables you to make your C/C++ driver source code portable across compilers from different vendors and, depending on your I/O application, portable across processor architectures and platforms.

The SG functions give you all the benefits of I/O standardization without generating any overhead in machine code. So you don't have to trade efficiency for portability. You can have both. These features make the SG method especially attractive for embedded program development.

All the I/O standardization requires is a little programming discipline!

Every access to I/O hardware from the source code must go through one of the SG functions below, instead of using the compiler's native (non-portable) syntax for I/O operations.

SG header files

All SG functions are prototyped in the header file <sgio.h>.

The access_type parameters used in the SG I/O functions below represent a complete description of the I/O access method for the given I/O register. In the I/O driver source code, access_type would simply be a symbolic name for the I/O register.

The access_type parameters (the symbolic I/O register names) are defined in the target specific header file <sgio_ta.h>; which is included in <sgio.h>

SG header files

Single I/O register addressing

These functions are used when addressing single I/O registers with a width of 8, 16, 32 bits or 1 bit.

/* Read operations: */
SGUCHAR sgrdby(access_type); /*  8-bit register */
SGUINT  sgrdwo(access_type); /* 16-bit register */
SGULONG sgrddw(access_type); /* 32-bit register */
SGBOOL  sgrdbi(access_type); /*  1-bit register */

/* Write operations: */
void sgwrby(access_type, SGUCHAR); /*  8-bit register */
void sgwrwo(access_type, SGUINT);  /* 16-bit register */
void sgwrdw(access_type, SGULONG); /* 32-bit register */
void sgwrbi(access_type, SGBOOL);  /*  1-bit register */

The I/O AND and OR functions below are used for setting and clearing (a group of) bits.

/* AND operations (Clear group of bits) */
void sgandby(access_type, SGUCHAR);
void sgandwo(access_type, SGUINT);
void sganddw(access_type, SGULONG);
void sgandbi(access_type, SGBOOL);

/* OR operations (Set group of bits) */
void sgorby(access_type, SGUCHAR);
void sgorwo(access_type, SGUINT);
void sgordw(access_type, SGULONG);
void sgorbi(access_type, SGBOOL);

Note: AND and OR operations on I/O are only valid (possible) when the I/O register hardware itself supports both read and write operations (i.e. read-modify-write operations)

I/O buffer register addressing

I/O functions for operation on I/O circuitry with internal buffers or multiple registers, e.g. a peripheral chip with a linear hardware buffer. The index parameter is the offset in a linear register array starting from the I/O location specified by access_type.

/* Read operations on hardware buffers: */
SGUCHAR sgrdbuf(  access_type, unsigned int index);
SGUINT  sgrdbufwo(access_type, unsigned int index);
SGULONG sgrdbufdw(access_type, unsigned int index);

/* Write operations on hardware buffers: */
void sgwrbuf(  access_type, unsigned int index, SGUCHAR dat);
void sgwrbufwo(access_type, unsigned int index, SGUINT dat);
void sgwrbufdw(access_type, unsigned int index, SGULONG dat);

/* AND operations on hardware buffers: */
void sgandbuf(  access_type, unsigned int index, SGUCHAR dat);
void sgandbufwo(access_type, unsigned int index, SGUINT dat);
void sgandbufdw(access_type, unsigned int index, SGULONG dat);

/* OR operations on hardware buffers: */
void sgorbuf(  access_type, unsigned int index, SGUCHAR dat);
void sgorbufwo(access_type, unsigned int index, SGUINT dat);
void sgorbufdw(access_type, unsigned int index, SGULONG dat);

Fixed-sized data types

The fixed-sized data types allow I/O driver code to operate with data types which fit the bit width of the I/O register, irrespectively of how the standard C data types are implemented by the compiler.

#define SGCHAR  signed char   /*  8-bit data type */
#define SGINT   signed int    /* 16-bit data type */
#define SGLONG  signed long   /* 32-bit data type */

#define SGUCHAR unsigned char /*  8-bit data type */
#define SGUINT  unsigned int  /* 16-bit data type */
#define SGULONG unsigned long /* 32-bit data type */

#define SGBOOL  bit           /* Boolean data type */

SG types are mapped to the most suitable data type for the given compiler. The SG types are defined in <sgtypes.h>.

Interrupt functions

The SG method standardizes the syntax for the most common interrupt-related operations with 3 functions (macros). Two of the macros are for enabling and disabling (global) interrupts:

SGENABLE;  /* Interrupt enable macro */
SGDISABLE; /* Interrupt disable macro */

These functions will either operate on the global interrupt-enable flag or shift between two interrupt priority levels, depending on the actual processor architecture.

The third macro standardizes interrupt functions with a uniform function header containing 3 parameters: the interrupt function name, the interrupt vector number, and a processor-specific option parameter.

/* Standardized interrupt function header macro */
SGISR( int_funcname, intr_vector_no, intr_option)
   { /* .. */ }

Interrupt functions are always treated as being processor-specific because of the vector number. However, the SG syntax makes the source code portable across different compilers for the same processor.

These RAMTEX product groups use the SG syntax to create source code portability across compilers and processor types: