moved all arch dependent byte swapping code to this file
This commit is contained in:
@@ -32,152 +32,303 @@
|
||||
// The default assumption is that the local floating point format is
|
||||
// IEEE and that these routines only need to perform byte swapping
|
||||
// as a side effect of copying an aligned operand into an unaligned
|
||||
// network byte stream.
|
||||
// network byte stream. OS specific code can provide a alternative
|
||||
// for this file if that assumption is wrong.
|
||||
//
|
||||
|
||||
// this endian test will hopefully vanish during optimization
|
||||
// and therefore be executed only at compile time
|
||||
union endianTest {
|
||||
/*
|
||||
* Here are the definitions for architecture dependent byte ordering
|
||||
* and floating point format.
|
||||
*/
|
||||
#if defined (_M_IX86) || defined (_X86_) || defined (__i386__) || defined (_X86_64_)
|
||||
# define EPICS_LITTLE_ENDIAN
|
||||
#elif ( defined (__ALPHA) || defined (__alpha) )
|
||||
# define EPICS_LITTLE_ENDIAN
|
||||
#elif defined (__arm__)
|
||||
# define EPICS_LITTLE_ENDIAN
|
||||
#else
|
||||
# define EPICS_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
/*
|
||||
* EPICS_CONVERSION_REQUIRED is set if either the byte order
|
||||
* or the floating point are not exactly big endian and ieee fp.
|
||||
* This can be set by hand above for a specific architecture
|
||||
* should there be an architecture that is a weird middle endian
|
||||
* ieee floating point format that is also big endian integer.
|
||||
*/
|
||||
#if ! defined ( EPICS_BIG_ENDIAN ) && ! defined ( EPICS_CONVERSION_REQUIRED )
|
||||
# define EPICS_CONVERSION_REQUIRED
|
||||
#endif
|
||||
|
||||
/*
|
||||
* some architecture sanity checks
|
||||
*/
|
||||
#if defined(EPICS_BIG_ENDIAN) && defined(EPICS_LITTLE_ENDIAN)
|
||||
# error defined(EPICS_BIG_ENDIAN) && defined(EPICS_LITTLE_ENDIAN)
|
||||
#endif
|
||||
#if !defined(EPICS_BIG_ENDIAN) && !defined(EPICS_LITTLE_ENDIAN)
|
||||
# error !defined(EPICS_BIG_ENDIAN) && !defined(EPICS_LITTLE_ENDIAN)
|
||||
#endif
|
||||
|
||||
//
|
||||
// The ARM supports two different floating point architectures, the
|
||||
// original and a more recent "vector" format. The original FPU is
|
||||
// emulated by the Netwinder library and, in little endian mode, has
|
||||
// the two words in the opposite order to that which would otherwise
|
||||
// be expected! The vector format is identical to IEEE.
|
||||
//
|
||||
#if defined (_ARM_NWFP_)
|
||||
# define EPICS_32107654_FP_ENDIAN
|
||||
#endif
|
||||
|
||||
//
|
||||
// Aligned wire format get/set can be implemented more efficently if
|
||||
// we know what type of endian it is
|
||||
//
|
||||
|
||||
inline epicsUInt16 byteSwap ( const epicsUInt16 & src )
|
||||
{
|
||||
# if defined ( EPICS_LITTLE_ENDIAN )
|
||||
return ( src << 8u ) | ( src >> 8u );
|
||||
# elif defined ( EPICS_BIG_ENDIAN )
|
||||
return src;
|
||||
# else
|
||||
# error undefined endian type
|
||||
# endif
|
||||
}
|
||||
|
||||
inline epicsUInt32 byteSwap ( const epicsUInt32 & src )
|
||||
{
|
||||
# if defined ( EPICS_LITTLE_ENDIAN )
|
||||
epicsUInt16 tmp0 = src >> 16u;
|
||||
epicsUInt16 tmp1 = src;
|
||||
tmp0 = ( tmp0 << 8u ) | ( tmp0 >> 8u );
|
||||
tmp1 = ( tmp1 << 8u ) | ( tmp1 >> 8u );
|
||||
return ( tmp1 << 16u ) | tmp0;
|
||||
# elif defined ( EPICS_BIG_ENDIAN )
|
||||
return src;
|
||||
# else
|
||||
# error undefined endian type
|
||||
# endif
|
||||
}
|
||||
|
||||
inline epicsInt16 byteSwap ( const epicsInt16 & src )
|
||||
{
|
||||
return static_cast < epicsInt16 > (
|
||||
byteSwap ( * reinterpret_cast < const epicsUInt16 * > ( & src ) ) );
|
||||
}
|
||||
|
||||
inline epicsInt32 byteSwap ( const epicsInt32 & src )
|
||||
{
|
||||
return static_cast < epicsInt32 > (
|
||||
byteSwap ( * reinterpret_cast < const epicsUInt32 * > ( & src ) ) );
|
||||
}
|
||||
|
||||
inline epicsFloat32 byteSwap ( const epicsFloat32 & src )
|
||||
{
|
||||
union {
|
||||
epicsUInt32 _u;
|
||||
epicsFloat32 _f;
|
||||
} tmp;
|
||||
tmp._u = byteSwap ( * reinterpret_cast < const epicsUInt32 * > ( & src ) );
|
||||
return tmp._f;
|
||||
}
|
||||
|
||||
inline epicsFloat64 byteSwap ( const epicsFloat64 & src )
|
||||
{
|
||||
# if defined ( EPICS_32107654_FP_ENDIAN )
|
||||
union {
|
||||
epicsUInt32 _u[2];
|
||||
epicsFloat64 _f;
|
||||
} tmp;
|
||||
const epicsUInt32 * pSrc =
|
||||
reinterpret_cast < const epicsUInt32 * > ( & src );
|
||||
tmp._u[0] = byteSwap ( pSrc[0] );
|
||||
tmp._u[1] = byteSwap ( pSrc[1] );
|
||||
return tmp._f;
|
||||
# elif defined ( EPICS_LITTLE_ENDIAN )
|
||||
union {
|
||||
epicsUInt32 _u[2];
|
||||
epicsFloat64 _f;
|
||||
} tmp;
|
||||
const epicsUInt32 * pSrc =
|
||||
reinterpret_cast < const epicsUInt32 * > ( & src );
|
||||
epicsUInt32 tmpUInt32 = byteSwap ( pSrc[0] );
|
||||
tmp._u[0] = byteSwap ( pSrc[1] );
|
||||
tmp._u[1] = tmpUInt32;
|
||||
return tmp._f;
|
||||
# elif defined ( EPICS_BIG_ENDIAN )
|
||||
return src;
|
||||
# else
|
||||
# error undefined endian type
|
||||
# endif
|
||||
}
|
||||
|
||||
//
|
||||
// With future CA protocols user defined payload composition will be
|
||||
// supported and we will need to move away from a naturally aligned
|
||||
// protcol (because pad bye overhead will probably be excessive when
|
||||
// maintaining 8 byte natural alignment if the user isnt thinking about
|
||||
// placing like sized elements together).
|
||||
//
|
||||
// Nevertheless, the R3.14 protocol continues to be naturally aligned,
|
||||
// and all of the fields within the DBR_XXXX types are naturally aligned.
|
||||
// Therefore we support here two wire transfer interfaces (naturally
|
||||
// aligned and otherwise) because there are important optimizations
|
||||
// specific to each of them.
|
||||
//
|
||||
// At some point in the future the naturally aligned interfaces might
|
||||
// be eliminated (or unbundled from base) should they be no-longer needed.
|
||||
//
|
||||
|
||||
template < class T >
|
||||
class AlignedWireRef {
|
||||
public:
|
||||
endianTest () : uint ( 1 ) {}
|
||||
bool littleEndian () const { return ( uchar[0] == 1 ); }
|
||||
bool bigEndian () const { return ! littleEndian(); }
|
||||
AlignedWireRef ( T & ref );
|
||||
operator T () const;
|
||||
AlignedWireRef < T > & operator = ( const T & );
|
||||
private:
|
||||
unsigned uint;
|
||||
unsigned char uchar[sizeof(unsigned)];
|
||||
T & _ref;
|
||||
};
|
||||
|
||||
static const endianTest endianTester;
|
||||
template < class T >
|
||||
class AlignedWireRef < const T > {
|
||||
public:
|
||||
AlignedWireRef ( const T & ref );
|
||||
operator T () const;
|
||||
private:
|
||||
const T & _ref;
|
||||
};
|
||||
|
||||
inline void osiConvertToWireFormat (
|
||||
const epicsFloat32 & value, epicsUInt8 * pWire )
|
||||
template < class T >
|
||||
inline AlignedWireRef < T > :: AlignedWireRef ( T & ref ) :
|
||||
_ref ( ref )
|
||||
{
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline AlignedWireRef < T > :: operator T () const
|
||||
{
|
||||
return byteSwap ( _ref );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline AlignedWireRef < T > & AlignedWireRef < T > :: operator = ( const T & src )
|
||||
{
|
||||
_ref = byteSwap ( src );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline AlignedWireRef < const T > :: AlignedWireRef ( const T & ref ) :
|
||||
_ref ( ref )
|
||||
{
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline AlignedWireRef < const T > :: operator T () const
|
||||
{
|
||||
return byteSwap ( _ref );
|
||||
}
|
||||
|
||||
epicsUInt16 WireGetUInt16 ( const epicsUInt8 * pWireSrc );
|
||||
epicsUInt32 WireGetUInt32 ( const epicsUInt8 * pWireSrc );
|
||||
epicsFloat32 WireGetFloat32 ( const epicsUInt8 * pWireSrc );
|
||||
epicsFloat64 WireGetFloat64 ( const epicsUInt8 * pWireSrc );
|
||||
|
||||
void WireSetUInt16 ( const epicsUInt16, epicsUInt8 * pWireDst );
|
||||
void WireSetUInt32 ( const epicsUInt32, epicsUInt8 * pWireDst );
|
||||
void WireSetFloat32 ( const epicsFloat32, epicsUInt8 * pWireDst );
|
||||
void WireSetFloat64 ( const epicsFloat64 &, epicsUInt8 * pWireDst );
|
||||
|
||||
//
|
||||
// We still use a big endian wire format for CA consistent with the internet,
|
||||
// but inconsistent with the vast majority of CPUs
|
||||
//
|
||||
|
||||
//
|
||||
// Missaligned wire format get/set can be implemented genrically w/o
|
||||
// performance penalty
|
||||
//
|
||||
inline epicsUInt16 WireGetUInt16 ( const epicsUInt8 * pWireSrc )
|
||||
{
|
||||
return
|
||||
( static_cast < epicsUInt16 > ( pWireSrc[0] ) << 8u ) |
|
||||
static_cast < epicsUInt16 > ( pWireSrc[1] );
|
||||
}
|
||||
inline epicsUInt32 WireGetUInt32 ( const epicsUInt8 * pWireSrc )
|
||||
{
|
||||
return
|
||||
( static_cast < epicsUInt32 > ( pWireSrc[0] ) << 24u ) |
|
||||
( static_cast < epicsUInt32 > ( pWireSrc[1] ) << 16u ) |
|
||||
( static_cast < epicsUInt32 > ( pWireSrc[2] ) << 8u ) |
|
||||
static_cast < epicsUInt32 > ( pWireSrc[3] );
|
||||
}
|
||||
inline epicsFloat32 WireGetFloat32 ( const epicsUInt8 * pWireSrc )
|
||||
{
|
||||
union {
|
||||
epicsUInt32 utmp;
|
||||
epicsFloat32 ftmp;
|
||||
} wireFloat32;
|
||||
wireFloat32.ftmp = value;
|
||||
pWire[0] = static_cast < epicsUInt8 > ( wireFloat32.utmp >> 24u );
|
||||
pWire[1] = static_cast < epicsUInt8 > ( wireFloat32.utmp >> 16u );
|
||||
pWire[2] = static_cast < epicsUInt8 > ( wireFloat32.utmp >> 8u );
|
||||
pWire[3] = static_cast < epicsUInt8 > ( wireFloat32.utmp >> 0u );
|
||||
epicsFloat32 _f;
|
||||
epicsUInt32 _u;
|
||||
} tmp;
|
||||
tmp._u = WireGetUInt32 ( pWireSrc );
|
||||
return tmp._f;
|
||||
}
|
||||
|
||||
inline void osiConvertToWireFormat (
|
||||
const epicsFloat64 & value, epicsUInt8 * pWire )
|
||||
inline epicsFloat64 WireGetFloat64 ( const epicsUInt8 * pWireSrc )
|
||||
{
|
||||
union {
|
||||
epicsUInt8 btmp[8];
|
||||
epicsFloat64 ftmp;
|
||||
} wireFloat64;
|
||||
wireFloat64.ftmp = value;
|
||||
// this endian test should vanish during optimization
|
||||
if ( endianTester.littleEndian () ) {
|
||||
// little endian
|
||||
pWire[0] = wireFloat64.btmp[7];
|
||||
pWire[1] = wireFloat64.btmp[6];
|
||||
pWire[2] = wireFloat64.btmp[5];
|
||||
pWire[3] = wireFloat64.btmp[4];
|
||||
pWire[4] = wireFloat64.btmp[3];
|
||||
pWire[5] = wireFloat64.btmp[2];
|
||||
pWire[6] = wireFloat64.btmp[1];
|
||||
pWire[7] = wireFloat64.btmp[0];
|
||||
}
|
||||
else {
|
||||
// big endian
|
||||
pWire[0] = wireFloat64.btmp[0];
|
||||
pWire[1] = wireFloat64.btmp[1];
|
||||
pWire[2] = wireFloat64.btmp[2];
|
||||
pWire[3] = wireFloat64.btmp[3];
|
||||
pWire[4] = wireFloat64.btmp[4];
|
||||
pWire[5] = wireFloat64.btmp[5];
|
||||
pWire[6] = wireFloat64.btmp[6];
|
||||
pWire[7] = wireFloat64.btmp[7];
|
||||
}
|
||||
epicsFloat64 _f;
|
||||
epicsUInt32 _u[2];
|
||||
} tmp;
|
||||
# if defined ( EPICS_BIG_ENDIAN ) || defined ( EPICS_32107654_FP_ENDIAN )
|
||||
tmp._u[0] = WireGetUInt32 ( pWireSrc );
|
||||
tmp._u[1] = WireGetUInt32 ( pWireSrc + 4 );
|
||||
# elif defined ( EPICS_LITTLE_ENDIAN )
|
||||
tmp._u[1] = WireGetUInt32 ( pWireSrc );
|
||||
tmp._u[0] = WireGetUInt32 ( pWireSrc + 4 );
|
||||
# else
|
||||
# error undefined endian type
|
||||
# endif
|
||||
return tmp._f;
|
||||
}
|
||||
|
||||
inline void osiConvertFromWireFormat (
|
||||
epicsFloat32 & value, const epicsUInt8 * pWire )
|
||||
inline void WireSetUInt16 ( const epicsUInt16 src, epicsUInt8 * pWireDst )
|
||||
{
|
||||
pWireDst[0] = static_cast < epicsUInt8 > ( src >> 8u );
|
||||
pWireDst[1] = static_cast < epicsUInt8 > ( src );
|
||||
}
|
||||
inline void WireSetUInt32 ( const epicsUInt32 src, epicsUInt8 * pWireDst )
|
||||
{
|
||||
pWireDst[0] = static_cast < epicsUInt8 > ( src >> 24u );
|
||||
pWireDst[1] = static_cast < epicsUInt8 > ( src >> 16u );
|
||||
pWireDst[2] = static_cast < epicsUInt8 > ( src >> 8u );
|
||||
pWireDst[3] = static_cast < epicsUInt8 > ( src );
|
||||
}
|
||||
inline void WireSetFloat32 ( const epicsFloat32 src, epicsUInt8 * pWireDst )
|
||||
{
|
||||
union {
|
||||
epicsUInt32 utmp;
|
||||
epicsFloat32 ftmp;
|
||||
} wireFloat32;
|
||||
wireFloat32.utmp =
|
||||
static_cast <epicsUInt32> (
|
||||
( pWire[0] << 24u ) | ( pWire[1] << 16u ) |
|
||||
( pWire[2] << 8u ) | pWire[3] );
|
||||
value = wireFloat32.ftmp;
|
||||
epicsFloat32 _f;
|
||||
epicsUInt32 _u;
|
||||
} tmp;
|
||||
tmp._f = src;
|
||||
WireSetUInt32 ( tmp._u, pWireDst );
|
||||
}
|
||||
|
||||
inline void osiConvertFromWireFormat (
|
||||
epicsFloat64 & value, const epicsUInt8 * pWire )
|
||||
inline void WireSetFloat64 ( const epicsFloat64 & src, epicsUInt8 * pWireDst )
|
||||
{
|
||||
union {
|
||||
epicsUInt8 btmp[8];
|
||||
epicsFloat64 ftmp;
|
||||
} wireFloat64;
|
||||
if ( endianTester.littleEndian () ) {
|
||||
wireFloat64.btmp[7] = pWire[0];
|
||||
wireFloat64.btmp[6] = pWire[1];
|
||||
wireFloat64.btmp[5] = pWire[2];
|
||||
wireFloat64.btmp[4] = pWire[3];
|
||||
wireFloat64.btmp[3] = pWire[4];
|
||||
wireFloat64.btmp[2] = pWire[5];
|
||||
wireFloat64.btmp[1] = pWire[6];
|
||||
wireFloat64.btmp[0] = pWire[7];
|
||||
}
|
||||
else {
|
||||
wireFloat64.btmp[0] = pWire[0];
|
||||
wireFloat64.btmp[1] = pWire[1];
|
||||
wireFloat64.btmp[2] = pWire[2];
|
||||
wireFloat64.btmp[3] = pWire[3];
|
||||
wireFloat64.btmp[4] = pWire[4];
|
||||
wireFloat64.btmp[5] = pWire[5];
|
||||
wireFloat64.btmp[6] = pWire[6];
|
||||
wireFloat64.btmp[7] = pWire[7];
|
||||
}
|
||||
value = wireFloat64.ftmp;
|
||||
}
|
||||
|
||||
inline epicsUInt16 epicsHTON16 ( epicsUInt16 in )
|
||||
{
|
||||
unsigned tmp = in; // avoid the usual unary conversions
|
||||
register union {
|
||||
epicsUInt8 bytes[2];
|
||||
epicsUInt16 word;
|
||||
} result;
|
||||
|
||||
result.bytes[0] = static_cast <epicsUInt8> ( tmp >> 8 );
|
||||
result.bytes[1] = static_cast <epicsUInt8> ( tmp );
|
||||
|
||||
return result.word;
|
||||
}
|
||||
|
||||
inline epicsUInt16 epicsNTOH16 ( epicsUInt16 in )
|
||||
{
|
||||
return epicsHTON16 ( in );
|
||||
}
|
||||
|
||||
inline epicsUInt32 epicsHTON32 ( epicsUInt32 in )
|
||||
{
|
||||
unsigned tmp = in; // avoid the usual unary conversions
|
||||
register union {
|
||||
epicsUInt8 bytes[4];
|
||||
epicsUInt32 longWord;
|
||||
} result;
|
||||
|
||||
result.bytes[0] = static_cast <epicsUInt8> ( tmp >> 24 );
|
||||
result.bytes[1] = static_cast <epicsUInt8> ( tmp >> 16 );
|
||||
result.bytes[2] = static_cast <epicsUInt8> ( tmp >> 8 );
|
||||
result.bytes[3] = static_cast <epicsUInt8> ( tmp >> 0 );
|
||||
|
||||
return result.longWord;
|
||||
}
|
||||
|
||||
inline epicsUInt32 epicsNTOH32 ( epicsUInt32 in )
|
||||
{
|
||||
return epicsHTON32 ( in );
|
||||
epicsFloat64 _f;
|
||||
epicsUInt32 _u[2];
|
||||
} tmp;
|
||||
tmp._f = src;
|
||||
# if defined ( EPICS_BIG_ENDIAN ) || defined ( EPICS_32107654_FP_ENDIAN )
|
||||
WireSetUInt32 ( tmp._u[0], pWireDst );
|
||||
WireSetUInt32 ( tmp._u[1], pWireDst + 4 );
|
||||
# elif defined ( EPICS_LITTLE_ENDIAN )
|
||||
WireSetUInt32 ( tmp._u[1], pWireDst );
|
||||
WireSetUInt32 ( tmp._u[0], pWireDst + 4 );
|
||||
# else
|
||||
# error undefined endian type
|
||||
# endif
|
||||
}
|
||||
|
||||
#endif // osiWireFormat
|
||||
|
||||
Reference in New Issue
Block a user