diff --git a/src/libCom/osi/os/VMS/osdWireFormat.h b/src/libCom/osi/os/VMS/osdWireFormat.h new file mode 100644 index 000000000..a6465085e --- /dev/null +++ b/src/libCom/osi/os/VMS/osdWireFormat.h @@ -0,0 +1,112 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE Versions 3.13.7 +* and higher are distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +// VMS specific wire formatting functions + +// +// We still use a big endian wire format for CA consistent with the internet, +// but inconsistent with the vast majority of CPUs +// + +#ifndef osdWireFormat +#define osdWireFormat + +#include + +#define EPICS_LITTLE_ENDIAN +#define EPICS_CONVERSION_REQUIRED + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsFloat32 & dst ) +{ + cvt$convert_float ( pWireSrc, CVT$K_IEEE_S, & dst, CVT$K_VAX_F, CVT$M_BIG_ENDIAN ); +} + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsFloat64 & dst ) +{ +# if defined ( __G_FLOAT ) && ( __G_FLOAT == 1 ) + cvt$convert_float ( pWireSrc, CVT$K_IEEE_T, & dst, CVT$K_VAX_G, CVT$M_BIG_ENDIAN ); +# else + cvt$convert_float ( pWireSrc, CVT$K_IEEE_T, & dst, CVT$K_VAX_D, CVT$M_BIG_ENDIAN ); +# endif +} + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsOldString & dst ) +{ + memcpy ( & dst, pWireSrc, sizeof ( dst ) ); +} + +inline void WireSet ( const epicsFloat32 & src, epicsUInt8 * pWireDst ) +{ + cvt$convert_float ( & src, CVT$K_VAX_F , pWireDst, CVT$K_IEEE_S, CVT$M_BIG_ENDIAN ); +} + +inline void WireSet ( const epicsFloat64 & src, epicsUInt8 * pWireDst ) +{ +# if defined ( __G_FLOAT ) && ( __G_FLOAT == 1 ) + cvt$convert_float ( & src, CVT$K_VAX_G , pWireDst, CVT$K_IEEE_T, CVT$M_BIG_ENDIAN ); +# else + cvt$convert_float ( & src, CVT$K_VAX_D , pWireDst, CVT$K_IEEE_T, CVT$M_BIG_ENDIAN ); +# endif +} + +inline void WireSet ( const epicsOldString & src, epicsUInt8 * pWireDst ) +{ + memcpy ( pWireDst, & src, sizeof ( src ) ); +} + +inline void AlignedWireGet ( const epicsUInt16 & src, epicsUInt16 & dst ) +{ + dst = byteSwap ( src ); +} + +inline void AlignedWireGet ( const epicsUInt32 & src, epicsUInt32 & dst ) +{ + dst = byteSwap ( src ); +} + +inline void AlignedWireGet ( const epicsFloat32 & src, epicsFloat32 & dst ) +{ + cvt$convert_float ( & src, CVT$K_IEEE_S, & dst, CVT$K_VAX_F, CVT$M_BIG_ENDIAN ); +} + +inline void AlignedWireGet ( const epicsFloat64 & src, epicsFloat64 & dst ) +{ +# if defined ( __G_FLOAT ) && ( __G_FLOAT == 1 ) + cvt$convert_float ( & src, CVT$K_IEEE_T, & dst, CVT$K_VAX_G, CVT$M_BIG_ENDIAN ); +# else + cvt$convert_float ( & src, CVT$K_IEEE_T, & dst, CVT$K_VAX_D, CVT$M_BIG_ENDIAN ); +# endif +} + +inline void AlignedWireSet ( const epicsUInt16 & src, epicsUInt16 & dst ) +{ + dst = byteSwap ( src ); +} + +inline void AlignedWireSet ( const epicsUInt32 & src, epicsUInt32 & dst ) +{ + dst = byteSwap ( src ); +} + +inline void AlignedWireSet ( const epicsFloat32 & src, epicsFloat32 & dst ) +{ + cvt$convert_float ( & src, CVT$K_VAX_F , & dst, CVT$K_IEEE_S, CVT$M_BIG_ENDIAN ); +} + +inline void AlignedWireSet ( const epicsFloat64 & src, epicsFloat64 & dst ) +{ +# if defined ( __G_FLOAT ) && ( __G_FLOAT == 1 ) + cvt$convert_float ( & src, CVT$K_VAX_G , & dst, CVT$K_IEEE_T, CVT$M_BIG_ENDIAN ); +# else + cvt$convert_float ( & src, CVT$K_VAX_D , & dst, CVT$K_IEEE_T, CVT$M_BIG_ENDIAN ); +# endif +} + +#endif // osdWireFormat \ No newline at end of file diff --git a/src/libCom/osi/os/default/osdWireFormat.h b/src/libCom/osi/os/default/osdWireFormat.h new file mode 100644 index 000000000..c485da591 --- /dev/null +++ b/src/libCom/osi/os/default/osdWireFormat.h @@ -0,0 +1,246 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE Versions 3.13.7 +* and higher are distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * + * + * L O S A L A M O S + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * + * Copyright, 2000, The Regents of the University of California. + * + * + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osdWireFormat +#define osdWireFormat + +#include + +// +// 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. OS specific code can provide a alternative +// for this file if that assumption is wrong. +// + +// +// Here are the definitions for architecture dependent byte ordering +// and floating point format. +// +// Perhaps the definition of EPICS_BIG_ENDIAN, EPICS_LITTLE_ENDIAN, +// and EPICS_32107654_FP_ENDIAN should be left to the build system +// so that this file need not be modified when adding support for a +// new architecture? +// +#if defined (_M_IX86) || defined (_X86_) || defined (__i386__) || defined (_X86_64_) || defined (_M_AMD64) +# 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 + +// +// We still use a big endian wire format for CA consistent with the internet, +// but inconsistent with the vast majority of CPUs +// + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsFloat64 & dst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + union { + epicsFloat64 _f; + epicsUInt32 _u[2]; + } tmp; +# if defined ( EPICS_BIG_ENDIAN ) || defined ( EPICS_32107654_FP_ENDIAN ) + WireGet ( pWireSrc, tmp._u[0] ); + WireGet ( pWireSrc + 4, tmp._u[1] ); +# elif defined ( EPICS_LITTLE_ENDIAN ) + WireGet ( pWireSrc, tmp._u[1] ); + WireGet ( pWireSrc + 4, tmp._u[0] ); +# else +# error undefined endian type +# endif + dst = tmp._f; +} + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsOldString & dst ) +{ + memcpy ( & dst, pWireSrc, sizeof ( dst ) ); +} + +inline void WireSet ( const epicsFloat64 & src, epicsUInt8 * pWireDst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + union { + epicsFloat64 _f; + epicsUInt32 _u[2]; + } tmp; + tmp._f = src; +# if defined ( EPICS_BIG_ENDIAN ) || defined ( EPICS_32107654_FP_ENDIAN ) + WireSet ( tmp._u[0], pWireDst ); + WireSet ( tmp._u[1], pWireDst + 4 ); +# elif defined ( EPICS_LITTLE_ENDIAN ) + WireSet ( tmp._u[1], pWireDst ); + WireSet ( tmp._u[0], pWireDst + 4 ); +# else +# error undefined endian type +# endif +} + +inline void WireSet ( const epicsOldString & src, epicsUInt8 * pWireDst ) +{ + memcpy ( pWireDst, & src, sizeof ( src ) ); +} + +inline void AlignedWireGet ( const epicsUInt16 & src, epicsUInt16 & dst ) +{ +# if defined ( EPICS_LITTLE_ENDIAN ) + dst = byteSwap ( src ); +# elif defined ( EPICS_BIG_ENDIAN ) + dst = src; +# else +# error undefined endian type +# endif +} + +inline void AlignedWireGet ( const epicsUInt32 & src, epicsUInt32 & dst ) +{ +# if defined ( EPICS_LITTLE_ENDIAN ) + dst = byteSwap ( src ); +# elif defined ( EPICS_BIG_ENDIAN ) + dst = src; +# else +# error undefined endian type +# endif +} + +inline void AlignedWireGet ( const epicsFloat64 & src, epicsFloat64 & dst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + union Swapper { + epicsUInt32 _u[2]; + epicsFloat64 _f; + }; +# if defined ( EPICS_32107654_FP_ENDIAN ) + Swapper tmp; + tmp._f = src; + AlignedWireGet ( tmp._u[0], tmp._u[0] ); + AlignedWireGet ( tmp._u[1], tmp._u[1] ); + dst = tmp._f; +# elif defined ( EPICS_LITTLE_ENDIAN ) + Swapper srcu, dstu; + srcu._f = src; + AlignedWireGet ( srcu._u[1], dstu._u[0] ); + AlignedWireGet ( srcu._u[0], dstu._u[1] ); + dst = dstu._f; +# elif defined ( EPICS_BIG_ENDIAN ) + dst = src; +# else +# error undefined endian type +# endif +} + +inline void AlignedWireSet ( const epicsUInt16 & src, epicsUInt16 & dst ) +{ +# if defined ( EPICS_LITTLE_ENDIAN ) + dst = byteSwap ( src ); +# elif defined ( EPICS_BIG_ENDIAN ) + dst = src; +# else +# error undefined endian type +# endif +} + +inline void AlignedWireSet ( const epicsUInt32 & src, epicsUInt32 & dst ) +{ +# if defined ( EPICS_LITTLE_ENDIAN ) + dst = byteSwap ( src ); +# elif defined ( EPICS_BIG_ENDIAN ) + dst = src; +# else +# error undefined endian type +# endif +} + +inline void AlignedWireSet ( const epicsFloat64 & src, epicsFloat64 & dst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + union Swapper { + epicsUInt32 _u[2]; + epicsFloat64 _f; + }; +# if defined ( EPICS_32107654_FP_ENDIAN ) + Swapper tmp; + tmp._f = src; + AlignedWireSet ( tmp._u[0], tmp._u[0] ); + AlignedWireSet ( tmp._u[1], tmp._u[1] ); + dst = tmp._f; +# elif defined ( EPICS_LITTLE_ENDIAN ) + Swapper srcu, dstu; + srcu._f = src; + AlignedWireSet ( srcu._u[1], dstu._u[0] ); + AlignedWireSet ( srcu._u[0], dstu._u[1] ); + dst = dstu._f; +# elif defined ( EPICS_BIG_ENDIAN ) + dst = src; +# else +# error undefined endian type +# endif +} + +#endif // osdWireFormat diff --git a/src/libCom/osi/osiWireFormat.h b/src/libCom/osi/osiWireFormat.h new file mode 100644 index 000000000..800e238ee --- /dev/null +++ b/src/libCom/osi/osiWireFormat.h @@ -0,0 +1,250 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* EPICS BASE Versions 3.13.7 +* and higher are distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * + * + * L O S A L A M O S + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * + * Copyright, 2000, The Regents of the University of California. + * + * + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef osiWireFormat +#define osiWireFormat + +#include "epicsTypes.h" + +// +// With future CA protocols user defined payload composition will be +// supported and we will need to move away from a naturally aligned +// protocol (because pad byte 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 > +void WireGet ( const epicsUInt8 * pWireSrc, T & ); + +template < class T > +void WireSet ( const T &, epicsUInt8 * pWireDst ); + +template < class T > +void AlignedWireGet ( const T &, T & ); + +template < class T > +void AlignedWireSet ( const T &, T & ); + +template < class T > +class AlignedWireRef { +public: + AlignedWireRef ( T & ref ); + operator T () const; + AlignedWireRef < T > & operator = ( const T & ); +private: + T & _ref; +}; + +template < class T > +class AlignedWireRef < const T > { +public: + AlignedWireRef ( const T & ref ); + operator T () const; +private: + const T & _ref; +}; + +template < class T > +inline AlignedWireRef < T > :: AlignedWireRef ( T & ref ) : + _ref ( ref ) +{ +} + +template < class T > +inline AlignedWireRef < T > :: operator T () const +{ + T tmp; + AlignedWireGet ( _ref, tmp ); + return tmp; +} + +template < class T > +inline AlignedWireRef < T > & AlignedWireRef < T > :: operator = ( const T & src ) +{ + AlignedWireSet ( src, _ref ); + 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 +{ + T tmp; + AlignedWireGet ( _ref, tmp ); + return tmp; +} + +// may be useful when creating support for little endian +inline epicsUInt16 byteSwap ( const epicsUInt16 & src ) +{ + return ( src << 8u ) | ( src >> 8u ); +} + +// may be useful when creating support for little endian +inline epicsUInt32 byteSwap ( const epicsUInt32 & src ) +{ + epicsUInt16 tmp0 = src >> 16u; + epicsUInt16 tmp1 = src; + tmp0 = ( tmp0 << 8u ) | ( tmp0 >> 8u ); + tmp1 = ( tmp1 << 8u ) | ( tmp1 >> 8u ); + return ( tmp1 << 16u ) | tmp0; +} + +template < class T > union WireAlias; + +template <> +union WireAlias < epicsInt8 > { + epicsUInt8 _u; + epicsInt8 _o; +}; + +template <> +union WireAlias < epicsInt16 > { + epicsUInt16 _u; + epicsInt16 _o; +}; + +template <> +union WireAlias < epicsInt32 > { + epicsUInt32 _u; + epicsInt32 _o; +}; + +template <> +union WireAlias < epicsFloat32 > { + epicsUInt32 _u; + epicsFloat32 _o; +}; + +// +// Missaligned unsigned wire format get/set can be implemented generically +// w/o performance penalty. Attempts to improve this on architectures that +// dont have alignement requirements will probably get into trouble with +// over-aggresive optimization under strict aliasing rules. +// + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsUInt8 & dst ) +{ + dst = pWireSrc[0]; +} + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsUInt16 & dst ) +{ + dst = + ( static_cast < epicsUInt16 > ( pWireSrc[0] ) << 8u ) | + static_cast < epicsUInt16 > ( pWireSrc[1] ); +} + +inline void WireGet ( const epicsUInt8 * pWireSrc, epicsUInt32 & dst ) +{ + dst = + ( static_cast < epicsUInt32 > ( pWireSrc[0] ) << 24u ) | + ( static_cast < epicsUInt32 > ( pWireSrc[1] ) << 16u ) | + ( static_cast < epicsUInt32 > ( pWireSrc[2] ) << 8u ) | + static_cast < epicsUInt32 > ( pWireSrc[3] ); +} + +template < class T > +inline void WireGet ( const epicsUInt8 * pWireSrc, T & dst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + WireAlias < T > tmp; + WireGet ( pWireSrc, tmp._u ); + dst = tmp._o; +} + +inline void WireSet ( const epicsUInt8 & src, epicsUInt8 * pWireDst ) +{ + pWireDst[0] = src; +} + +inline void WireSet ( const epicsUInt16 & src, epicsUInt8 * pWireDst ) +{ + pWireDst[0] = static_cast < epicsUInt8 > ( src >> 8u ); + pWireDst[1] = static_cast < epicsUInt8 > ( src ); +} + +inline void WireSet ( 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 ); +} + +template < class T > +inline void WireSet ( const T & src, epicsUInt8 * pWireDst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + WireAlias < T > tmp; + tmp._o = src; + WireSet ( tmp._u, pWireDst ); +} + +template < class T > +inline void AlignedWireGet ( const T & src, T & dst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + WireAlias < T > tmp; + tmp._o = src; + AlignedWireGet ( tmp._u, tmp._u ); + dst = tmp._o; +} + +template < class T > +inline void AlignedWireSet ( const T & src, T & dst ) +{ + // copy through union here + // a) prevents over-aggresive optimization under strict aliasing rules + // b) doesnt preclude extra copy operation being optimized away + WireAlias < T > tmp; + tmp._o = src; + AlignedWireSet ( tmp._u, tmp._u ); + dst = tmp._o; +} + +#include "osdWireFormat.h" + +#endif // osiWireFormat