add MMIO API

From devLib2
adds calls to handle 8, 16, and 32 bit
Memory Mapped I/O reads and writes.

Adds X_iowriteY() and X_ioreadY().

where X is nat (native), be, or le.
Y is 16 or 32.

Also adds ioread8() and iowrite8().
This commit is contained in:
Michael Davidsaver
2013-05-10 16:22:16 -04:00
parent 8d7a241d04
commit 6347b1daf9
5 changed files with 457 additions and 0 deletions

View File

@@ -61,6 +61,8 @@ INC += devLib.h
INC += devLibVME.h
INC += devLibVMEImpl.h
INC += osdVME.h
INC += epicsMMIO.h
INC += epicsMMIODef.h
Com_SRCS += epicsThread.cpp
Com_SRCS += epicsMutex.cpp

View File

@@ -0,0 +1,58 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
* Brookhaven National Laboratory.
* devLib2 is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Michael Davidsaver <mdavidsaver@bnl.gov>
*/
#ifndef EPICSMMIO_H
#define EPICSMMIO_H
#include <epicsEndian.h>
#if defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)
# include <libcpu/io.h>
/*NOTE: All READ/WRITE operations have an implicit read or write barrier */
# define ioread8(A) in_8((volatile epicsUInt8*)(A))
# define iowrite8(A,D) out_8((volatile epicsUInt8*)(A), D)
# define le_ioread16(A) in_le16((volatile epicsUInt16*)(A))
# define le_ioread32(A) in_le32((volatile epicsUInt32*)(A))
# define le_iowrite16(A,D) out_le16((volatile epicsUInt16*)(A), D)
# define le_iowrite32(A,D) out_le32((volatile epicsUInt32*)(A), D)
# define be_ioread16(A) in_be16((volatile epicsUInt16*)(A))
# define be_ioread32(A) in_be32((volatile epicsUInt32*)(A))
# define be_iowrite16(A,D) out_be16((volatile epicsUInt16*)(A), D)
# define be_iowrite32(A,D) out_be32((volatile epicsUInt32*)(A), D)
# define rbarr() iobarrier_r()
# define wbarr() iobarrier_w()
# define rwbarr() iobarrier_rw()
/* Define native operations */
# define nat_ioread16 be_ioread16
# define nat_ioread32 be_ioread32
# define nat_iowrite16 be_iowrite16
# define nat_iowrite32 be_iowrite32
#elif defined(i386) ||defined(__i386__) || defined(__i386)
/* X86 does not need special handling for read/write width.
*
* TODO: Memory barriers?
*/
#include "epicsMMIODef.h"
#else
# warning I/O operations not defined for this RTEMS architecture
#include "epicsMMIODef.h"
#endif /* if defined PPC */
#endif /* EPICSMMIO_H */

View File

@@ -0,0 +1,2 @@
#include "epicsMMIODef.h"

View File

@@ -0,0 +1,268 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
* Brookhaven National Laboratory.
* devLib2 is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Michael Davidsaver <mdavidsaver@bnl.gov>
*/
#ifndef EPICSMMIODEF_H
#define EPICSMMIODEF_H
#include <epicsTypes.h>
#include <epicsEndian.h>
#include <shareLib.h>
#ifdef __cplusplus
# ifndef INLINE
# define INLINE inline
# endif
#endif
/** @ingroup mmio
*@{
*/
/** @brief Read a single byte.
*/
INLINE
epicsUInt8
ioread8(volatile void* addr)
{
return *(volatile epicsUInt8*)(addr);
}
/** @brief Write a single byte.
*/
INLINE
void
iowrite8(volatile void* addr, epicsUInt8 val)
{
*(volatile epicsUInt8*)(addr) = val;
}
/** @brief Read two bytes in host order.
* Not byte swapping
*/
INLINE
epicsUInt16
nat_ioread16(volatile void* addr)
{
return *(volatile epicsUInt16*)(addr);
}
/** @brief Write two byte in host order.
* Not byte swapping
*/
INLINE
void
nat_iowrite16(volatile void* addr, epicsUInt16 val)
{
*(volatile epicsUInt16*)(addr) = val;
}
/** @brief Read four bytes in host order.
* Not byte swapping
*/
INLINE
epicsUInt32
nat_ioread32(volatile void* addr)
{
return *(volatile epicsUInt32*)(addr);
}
/** @brief Write four byte in host order.
* Not byte swapping
*/
INLINE
void
nat_iowrite32(volatile void* addr, epicsUInt32 val)
{
*(volatile epicsUInt32*)(addr) = val;
}
#if EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG
/** @ingroup mmio
*@{
*/
#define bswap16(value) ((epicsUInt16) ( \
(((epicsUInt16)(value) & 0x00ff) << 8) | \
(((epicsUInt16)(value) & 0xff00) >> 8)))
#define bswap32(value) ( \
(((epicsUInt32)(value) & 0x000000ff) << 24) | \
(((epicsUInt32)(value) & 0x0000ff00) << 8) | \
(((epicsUInt32)(value) & 0x00ff0000) >> 8) | \
(((epicsUInt32)(value) & 0xff000000) >> 24))
# define be_ioread16(A) nat_ioread16(A)
# define be_ioread32(A) nat_ioread32(A)
# define be_iowrite16(A,D) nat_iowrite16(A,D)
# define be_iowrite32(A,D) nat_iowrite32(A,D)
# define le_ioread16(A) bswap16(nat_ioread16(A))
# define le_ioread32(A) bswap32(nat_ioread32(A))
# define le_iowrite16(A,D) nat_iowrite16(A,bswap16(D))
# define le_iowrite32(A,D) nat_iowrite32(A,bswap32(D))
/** @} */
#elif EPICS_BYTE_ORDER == EPICS_ENDIAN_LITTLE
#include <arpa/inet.h>
#ifdef __rtems__
/* some rtems bsps (pc386) don't provide htonl correctly */
# include <rtems/endian.h>
#endif
/** @ingroup mmio
*@{
*/
/* hton* is optimized or a builtin for most compilers
* so use it if possible
*/
#define bswap16(v) htons(v)
#define bswap32(v) htonl(v)
# define be_ioread16(A) bswap16(nat_ioread16(A))
# define be_ioread32(A) bswap32(nat_ioread32(A))
# define be_iowrite16(A,D) nat_iowrite16(A,bswap16(D))
# define be_iowrite32(A,D) nat_iowrite32(A,bswap32(D))
# define le_ioread16(A) nat_ioread16(A)
# define le_ioread32(A) nat_ioread32(A)
# define le_iowrite16(A,D) nat_iowrite16(A,D)
# define le_iowrite32(A,D) nat_iowrite32(A,D)
/** @} */
#else
# error Unable to determine native byte order
#endif
/** @def bswap16
* @brief Unconditional two byte swap
*/
/** @def bswap32
* @brief Unconditional four byte swap
*/
/** @def be_ioread16
* @brief Read two byte in big endian order.
*/
/** @def be_iowrite16
* @brief Write two byte in big endian order.
*/
/** @def be_ioread32
* @brief Read four byte in big endian order.
*/
/** @def be_iowrite32
* @brief Write four byte in big endian order.
*/
/** @def le_ioread16
* @brief Read two byte in little endian order.
*/
/** @def le_iowrite16
* @brief Write two byte in little endian order.
*/
/** @def le_ioread32
* @brief Read four byte in little endian order.
*/
/** @def le_iowrite32
* @brief Write four byte in little endian order.
*/
/** @ingroup mmio
*@{
*/
/** @brief Explicit read memory barrier
* Prevents reordering of reads around it.
*/
#define rbarr() do{}while(0)
/** @brief Explicit write memory barrier
* Prevents reordering of writes around it.
*/
#define wbarr() do{}while(0)
/** @brief Explicit read/write memory barrier
* Prevents reordering of reads or writes around it.
*/
#define rwbarr() do{}while(0)
/** @} */
/** @defgroup mmio Memory Mapped I/O
*
* Safe operations on I/O memory.
*
*This files defines a set of macros for access to Memory Mapped I/O
*
*They are named T_ioread# and T_iowrite# where # can be 8, 16, or 32.
*'T' can either be 'le', 'be', or 'nat' (except ioread8 and
*iowrite8).
*
*The macros defined use OS specific extensions (when available)
*to ensure the following.
*
*@li Width. A 16 bit operation will not be broken into two 8 bit operations,
* or one half of a 32 bit operation.
*
*@li Order. Writes to two different registers will not be reordered.
* This only applies to MMIO operations, not between MMIO and
* normal memory operations.
*
*PCI access should use either 'le_' or 'be_' as determined by the
*device byte order.
*
*VME access should always use 'nat_'. If the device byte order is
*little endian then an explicit swap is required.
*
*@section mmioex Examples:
*
*@subsection mmioexbe Big endian device:
*
*@b PCI
*
@code
be_iowrite16(base+off, 14);
var = be_ioread16(base+off);
@endcode
*
*@b VME
*
@code
nat_iowrite16(base+off, 14);
var = nat_ioread16(base+off);
@endcode
*
*@subsection mmioexle Little endian device
*
*@b PCI
@code
le_iowrite16(base+off, 14);
var = le_ioread16(base+off);
@endcode
*@b VME
@code
nat_iowrite16(base+off, bswap16(14));
var = bswap16(nat_iowrite16(base+off));
@endcode
*This difference arises because VME bridges implement hardware byte
*swapping on little endian systems, while PCI bridges do not.
*Software accessing PCI devices must know if byte swapping is required.
*This conditional swap is implemented by the 'be_' and 'le_' macros.
*
*This is a fundamental difference between PCI and VME.
*
*Software accessing PCI @b must do conditional swapping.
*
*Software accessing VME must @b not do conditional swapping.
*
*@note All read and write operations have an implicit read or write barrier.
*/
#endif /* EPICSMMIODEF_H */

View File

@@ -0,0 +1,127 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven Science Associates, as Operator of
* Brookhaven National Laboratory.
* Copyright (c) 2006 The University of Chicago,
* as Operator of Argonne National Laboratory.
* Copyright (c) 2006 The Regents of the University of California,
* as Operator of Los Alamos National Laboratory.
* Copyright (c) 2006 The Board of Trustees of the Leland Stanford Junior
* University, as Operator of the Stanford Linear Accelerator Center.
* devLib2 is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Original Author: Eric Bjorklund (was called mrfSyncIO.h)
* Author: Michael Davidsaver <mdavidsaver@bnl.gov>
*/
#ifndef EPICSMMIO_H
#define EPICSMMIO_H
/**************************************************************************************************/
/* Required Header Files */
/**************************************************************************************************/
/* This is needed on vxWorks 6.8 */
#ifndef _VSB_CONFIG_FILE
# define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
#endif
#include <vxWorks.h> /* vxWorks common definitions */
#include <sysLib.h> /* vxWorks System Library Definitions */
#include <version.h> /* vxWorks Version Definitions */
#include <epicsTypes.h> /* EPICS Common Type Definitions */
#include <epicsEndian.h> /* EPICS Byte Order Definitions */
/*=====================
* vxAtomicLib.h (which defines the memory barrier macros)
* is available on vxWorks 6.6 and above.
*/
#if _WRS_VXWORKS_MAJOR > 6
# include <vxAtomicLib.h>
#elif _WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 6
# include <vxAtomicLib.h>
#endif
/**************************************************************************************************/
/* Function Prototypes for Routines Not Defined in sysLib.h */
/**************************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
epicsUInt16 sysIn16 (volatile void*); /* Synchronous 16 bit read */
epicsUInt32 sysIn32 (volatile void*); /* Synchronous 32 bit read */
void sysOut16 (volatile void*, epicsUInt16); /* Synchronous 16 bit write */
void sysOut32 (volatile void*, epicsUInt32); /* Synchronous 32 bit write */
#ifdef __cplusplus
}
#endif
#define bswap16(value) ((epicsUInt16) ( \
(((epicsUInt16)(value) & 0x00ff) << 8) | \
(((epicsUInt16)(value) & 0xff00) >> 8)))
#define bswap32(value) ( \
(((epicsUInt32)(value) & 0x000000ff) << 24) | \
(((epicsUInt32)(value) & 0x0000ff00) << 8) | \
(((epicsUInt32)(value) & 0x00ff0000) >> 8) | \
(((epicsUInt32)(value) & 0xff000000) >> 24))
#if EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG
# define be16_to_cpu(X) (X)
# define be32_to_cpu(X) (X)
# define le16_to_cpu(X) bswap16(X)
# define le32_to_cpu(X) bswap32(X)
#elif EPICS_BYTE_ORDER == EPICS_ENDIAN_LITTLE
# define be16_to_cpu(X) bswap16(X)
# define be32_to_cpu(X) bswap32(X)
# define le16_to_cpu(X) (X)
# define le32_to_cpu(X) (X)
#else
# error Unable to determine native byte order
#endif
#define ioread8(address) sysInByte ((epicsUInt32)(address))
#define iowrite8(address,data) sysOutByte ((epicsUInt32)(address), (epicsUInt8)(data))
#define nat_ioread16(address) sysIn16 ((address))
#define nat_ioread32(address) sysIn32 ((address))
#define nat_iowrite16(address,data) sysOut16(address,data)
#define nat_iowrite32(address,data) sysOut32(address,data)
#define be_ioread16(address) be16_to_cpu (sysIn16 ((address)))
#define be_ioread32(address) be32_to_cpu (sysIn32 ((address)))
#define be_iowrite16(address,data) sysOut16 ((address), be16_to_cpu((epicsUInt16)(data)))
#define be_iowrite32(address,data) sysOut32 ((address), be32_to_cpu((epicsUInt32)(data)))
#define le_ioread16(address) le16_to_cpu (sysIn16 ((address)))
#define le_ioread32(address) le32_to_cpu (sysIn32 ((address)))
#define le_iowrite16(address,data) sysOut16 ((address), le16_to_cpu((epicsUInt16)(data)))
#define le_iowrite32(address,data) sysOut32 ((address), le32_to_cpu((epicsUInt32)(data)))
#ifndef VX_MEM_BARRIER_R
# define VX_MEM_BARRIER_R() do{}while(0)
#endif
#ifndef VX_MEM_BARRIER_W
# define VX_MEM_BARRIER_W() do{}while(0)
#endif
#ifndef VX_MEM_BARRIER_RW
# define VX_MEM_BARRIER_RW() do{}while(0)
#endif
#define rbarr() VX_MEM_BARRIER_R()
#define wbarr() VX_MEM_BARRIER_W()
#define rwbarr() VX_MEM_BARRIER_RW()
#endif /* EPICSMMIO_H */