From 31be41653a659a52460734cb8fe1da27e6d5629e Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Mon, 20 Apr 2015 11:08:22 +0200 Subject: timecounter: Port to RTEMS New test sptests/timecounter01. Update #2271. --- cpukit/sapi/Makefile.am | 3 + cpukit/sapi/include/rtems/bsd.h | 141 +++++++++++++++ cpukit/sapi/include/rtems/timecounter.h | 304 ++++++++++++++++++++++++++++++++ cpukit/sapi/preinstall.am | 8 + cpukit/sapi/src/tcsimpleinstall.c | 52 ++++++ 5 files changed, 508 insertions(+) create mode 100644 cpukit/sapi/include/rtems/bsd.h create mode 100644 cpukit/sapi/include/rtems/timecounter.h create mode 100644 cpukit/sapi/src/tcsimpleinstall.c (limited to 'cpukit/sapi') diff --git a/cpukit/sapi/Makefile.am b/cpukit/sapi/Makefile.am index 070800e636..d7fd9aac63 100644 --- a/cpukit/sapi/Makefile.am +++ b/cpukit/sapi/Makefile.am @@ -4,6 +4,7 @@ include $(top_srcdir)/automake/compile.am include_rtemsdir = $(includedir)/rtems include_rtems_HEADERS = include/confdefs.h +include_rtems_HEADERS += include/rtems/bsd.h include_rtems_HEADERS += include/rtems/chain.h include_rtems_HEADERS += include/rtems/config.h include_rtems_HEADERS += include/rtems/counter.h @@ -19,6 +20,7 @@ include_rtems_HEADERS += include/rtems/rbheap.h include_rtems_HEADERS += include/rtems/rbtree.h include_rtems_HEADERS += include/rtems/scheduler.h include_rtems_HEADERS += include/rtems/sptables.h +include_rtems_HEADERS += include/rtems/timecounter.h include_rtems_HEADERS += include/rtems/timespec.h EXTRA_DIST = include/rtems/README @@ -39,6 +41,7 @@ libsapi_a_SOURCES += src/delayticks.c libsapi_a_SOURCES += src/delaynano.c libsapi_a_SOURCES += src/profilingiterate.c libsapi_a_SOURCES += src/profilingreportxml.c +libsapi_a_SOURCES += src/tcsimpleinstall.c libsapi_a_CPPFLAGS = $(AM_CPPFLAGS) include $(srcdir)/preinstall.am diff --git a/cpukit/sapi/include/rtems/bsd.h b/cpukit/sapi/include/rtems/bsd.h new file mode 100644 index 0000000000..0c44e3787d --- /dev/null +++ b/cpukit/sapi/include/rtems/bsd.h @@ -0,0 +1,141 @@ +/** + * @file + * + * @ingroup BSD + * + * @brief BSD Compatibility API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_BSD_H +#define _RTEMS_BSD_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup BSD BSD Compatibility Support + * + * @{ + */ + +/** + * @copydoc _Timecounter_Bintime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_bintime( struct bintime *bt ) +{ + _Timecounter_Bintime( bt ); +} + +/** + * @copydoc _Timecounter_Nanotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_nanotime( struct timespec *ts ) +{ + _Timecounter_Nanotime( ts ); +} + +/** + * @copydoc _Timecounter_Microtime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_microtime( struct timeval *tv ) +{ + _Timecounter_Microtime( tv ); +} + +/** + * @copydoc _Timecounter_Binuptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_binuptime( struct bintime *bt ) +{ + _Timecounter_Binuptime( bt ); +} + +/** + * @copydoc _Timecounter_Nanouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_nanouptime( struct timespec *ts ) +{ + _Timecounter_Nanouptime( ts ); +} + +/** + * @copydoc _Timecounter_Microtime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_microuptime( struct timeval *tv ) +{ + _Timecounter_Microuptime( tv ); +} + +/** + * @copydoc _Timecounter_Getbintime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getbintime( struct bintime *bt ) +{ + _Timecounter_Getbintime( bt ); +} + +/** + * @copydoc _Timecounter_Getnanotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getnanotime( struct timespec *ts ) +{ + _Timecounter_Getnanotime( ts ); +} + +/** + * @copydoc _Timecounter_Getmicrotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getmicrotime( struct timeval *tv ) +{ + _Timecounter_Getmicrotime( tv ); +} + +/** + * @copydoc _Timecounter_Getbinuptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getbinuptime( struct bintime *bt ) +{ + _Timecounter_Getbinuptime( bt ); +} + +/** + * @copydoc _Timecounter_Getnanouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getnanouptime( struct timespec *ts ) +{ + _Timecounter_Getnanouptime( ts ); +} + +/** + * @copydoc _Timecounter_Getmicrouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getmicrouptime( struct timeval *tv ) +{ + _Timecounter_Getmicrouptime( tv ); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_BSD_H */ diff --git a/cpukit/sapi/include/rtems/timecounter.h b/cpukit/sapi/include/rtems/timecounter.h new file mode 100644 index 0000000000..04bc534d55 --- /dev/null +++ b/cpukit/sapi/include/rtems/timecounter.h @@ -0,0 +1,304 @@ +/** + * @file + * + * @ingroup SAPITimecounter + * + * @brief Timecounter API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_TIMECOUNTER_H +#define _RTEMS_TIMECOUNTER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup SAPITimecounter Timecounter Support + * + * @{ + */ + +/** + * @brief Timecounter quality for the clock drivers. + * + * Timecounter with higher quality value are used in favour of those with lower + * quality value. + */ +#define RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER 100 + +/** + * @copydoc _Timecounter_Install() + * + * Below is an exemplary code snippet that shows the adjustable parameters and + * the following call of the install routine. + * + * @code + * struct timecounter tc; + * + * uint32_t get_timecount( struct timecounter *tc ) + * { + * return some_free_running_counter; + * } + * + * void install( void ) + * { + * tc.tc_get_timecount = get_timecount; + * tc.tc_counter_mask = 0xffffffff; + * tc.tc_frequency = 123456; + * tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + * rtems_timecounter_install( &tc ); + * } + * @endcode + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_install( + struct timecounter *tc +) +{ + _Timecounter_Install( tc ); +} + +/** + * @copydoc _Timecounter_Tick() + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_tick(void) +{ + _Timecounter_Tick(); +} + +/** + * @brief Simple timecounter to support legacy clock drivers. + */ +typedef struct { + struct timecounter tc; + uint64_t scaler; + uint32_t real_interval; + uint32_t binary_interval; +} rtems_timecounter_simple; + +/** + * @brief Returns the current value of a simple timecounter. + */ +typedef uint32_t rtems_timecounter_simple_get( + rtems_timecounter_simple *tc +); + +/** + * @brief Returns true if the interrupt of a simple timecounter is pending, and + * false otherwise. + */ +typedef bool rtems_timecounter_simple_is_pending( + rtems_timecounter_simple *tc +); + +/** + * @brief Initializes and installs a simple timecounter. + * + * A simple timecounter can be used if the hardware provides no free running + * counter or only the module used for the clock tick is available. The period + * of the simple timecounter equals the clock tick interval. The interval is + * scaled up to the next power of two. + * + * @param[in] tc Zero initialized simple timecounter. + * @param[in] frequency_in_hz The timecounter frequency in Hz. + * @param[in] timecounter_ticks_per_clock_tick The timecounter ticks per clock tick. + * @param[in] get_timecount The method to get the current time count. + * + * @code + * #include + * + * static rtems_timecounter_simple some_tc; + * + * static uint32_t some_tc_get( rtems_timecounter_simple *tc ) + * { + * return some.value; + * } + * + * static bool some_tc_is_pending( rtems_timecounter_simple *tc ) + * { + * return some.is_pending; + * } + * + * static uint32_t some_tc_get_timecount( struct timecounter *tc ) + * { + * return rtems_timecounter_simple_downcounter_get( + * tc, + * some_tc_get, + * some_tc_is_pending + * ); + * } + * + * static void some_tc_tick( void ) + * { + * rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get ); + * } + * + * void install( void ) + * { + * uint32_t frequency = 123456; + * uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + * uint32_t timecounter_ticks_per_clock_tick = + * ( frequency * us_per_tick ) / 1000000; + * + * rtems_timecounter_simple_install( + * &some_tc, + * frequency, + * timecounter_ticks_per_clock_tick, + * some_tc_get_timecount + * ); + * } + * @endcode + * + * @see rtems_timecounter_simple_downcounter_get(), + * rtems_timecounter_simple_downcounter_tick(), + * rtems_timecounter_simple_upcounter_get() and + * rtems_timecounter_simple_upcounter_tick(). + */ +void rtems_timecounter_simple_install( + rtems_timecounter_simple *tc, + uint32_t frequency_in_hz, + uint32_t timecounter_ticks_per_clock_tick, + timecounter_get_t *get_timecount +); + +/** + * @brief Maps a simple timecounter value into its binary frequency domain. + * + * @param[in] tc The simple timecounter. + * @param[in] value The value of the simple timecounter. + * + * @return The scaled value. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_scale( + const rtems_timecounter_simple *tc, + uint32_t value +) +{ + return (uint32_t) ( ( value * tc->scaler ) >> 32 ); +} + +/** + * @brief Performs a simple timecounter tick for downcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_downcounter_tick( + rtems_timecounter_simple *tc, + rtems_timecounter_simple_get get +) +{ + uint32_t current; + + current = rtems_timecounter_simple_scale( + tc, + tc->real_interval - ( *get )( tc ) + ); + + _Timecounter_Tick_simple( tc->binary_interval, current ); +} + +/** + * @brief Performs a simple timecounter tick for upcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_upcounter_tick( + rtems_timecounter_simple *tc, + rtems_timecounter_simple_get get +) +{ + uint32_t current; + + current = rtems_timecounter_simple_scale( tc, ( *get )( tc ) ); + + _Timecounter_Tick_simple( tc->binary_interval, current ); +} + +/** + * @brief Gets the simple timecounter value mapped to its binary frequency + * domain for downcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + * @param[in] is_pending The method which indicates if the interrupt of the + * simple timecounter is pending. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_downcounter_get( + struct timecounter *tc_base, + rtems_timecounter_simple_get get, + rtems_timecounter_simple_is_pending is_pending +) +{ + rtems_timecounter_simple *tc; + uint32_t counter; + uint32_t interval; + + tc = (rtems_timecounter_simple *) tc_base; + counter = ( *get )( tc ); + interval = tc->real_interval; + + if ( ( *is_pending )( tc ) ) { + counter = ( *get )( tc ); + interval *= 2; + } + + return rtems_timecounter_simple_scale( tc, interval - counter ); +} + +/** + * @brief Gets the simple timecounter value mapped to its binary frequency + * domain for upcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + * @param[in] is_pending The method which indicates if the interrupt of the + * simple timecounter is pending. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_upcounter_get( + struct timecounter *tc_base, + rtems_timecounter_simple_get get, + rtems_timecounter_simple_is_pending is_pending +) +{ + rtems_timecounter_simple *tc; + uint32_t counter; + uint32_t interval; + + tc = (rtems_timecounter_simple *) tc_base; + counter = ( *get )( tc ); + interval = 0; + + if ( ( *is_pending )( tc ) ) { + counter = ( *get )( tc ); + interval = tc->real_interval; + } + + return rtems_timecounter_simple_scale( tc, interval + counter ); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_TIMECOUNTER_H */ diff --git a/cpukit/sapi/preinstall.am b/cpukit/sapi/preinstall.am index 3f864bb61d..8a4e54ffd2 100644 --- a/cpukit/sapi/preinstall.am +++ b/cpukit/sapi/preinstall.am @@ -22,6 +22,10 @@ $(PROJECT_INCLUDE)/rtems/confdefs.h: include/confdefs.h $(PROJECT_INCLUDE)/rtems $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/confdefs.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/confdefs.h +$(PROJECT_INCLUDE)/rtems/bsd.h: include/rtems/bsd.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bsd.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bsd.h + $(PROJECT_INCLUDE)/rtems/chain.h: include/rtems/chain.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/chain.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/chain.h @@ -82,6 +86,10 @@ $(PROJECT_INCLUDE)/rtems/sptables.h: include/rtems/sptables.h $(PROJECT_INCLUDE) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/sptables.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/sptables.h +$(PROJECT_INCLUDE)/rtems/timecounter.h: include/rtems/timecounter.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/timecounter.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/timecounter.h + $(PROJECT_INCLUDE)/rtems/timespec.h: include/rtems/timespec.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/timespec.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/timespec.h diff --git a/cpukit/sapi/src/tcsimpleinstall.c b/cpukit/sapi/src/tcsimpleinstall.c new file mode 100644 index 0000000000..563edd7c87 --- /dev/null +++ b/cpukit/sapi/src/tcsimpleinstall.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +void rtems_timecounter_simple_install( + rtems_timecounter_simple *tc, + uint32_t frequency_in_hz, + uint32_t counter_ticks_per_clock_tick, + timecounter_get_t *get_timecount +) +{ + uint32_t power_of_two = 1; + uint32_t mask; + uint64_t scaler; + int i; + + for ( i = 0; i < 32; ++i ) { + if ( power_of_two >= counter_ticks_per_clock_tick ) { + break; + } + + power_of_two *= 2; + } + + mask = ( 2 * power_of_two ) - 1; + scaler = ( (uint64_t) power_of_two << 32 ) / counter_ticks_per_clock_tick; + + tc->scaler = scaler; + tc->real_interval = counter_ticks_per_clock_tick; + tc->binary_interval = ( mask + 1 ) / 2; + tc->tc.tc_get_timecount = get_timecount; + tc->tc.tc_counter_mask = mask; + tc->tc.tc_frequency = (uint32_t) ( ( frequency_in_hz * scaler ) >> 32 ); + tc->tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + _Timecounter_Install( &tc->tc ); +} -- cgit v1.2.3