From 05655a9d881c6dee8bcafebf3c18353b55a792a2 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 16 Mar 2017 17:57:57 +0100 Subject: [PATCH] hw cortex-a9 timer: raise translation precision If we do the tics-to-us translation with one division and multiplication over the whole argument, like before, we loose microseconds granularity although the timer frequency allows for such granularity. Thus, we treat the most significant half and the least significant half of the tics value separate. Each half is shifted to the best bit position for the translation, then translated, and then shifted back. Ref #2347 --- .../src/core/include/spec/cortex_a9/timer.h | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/repos/base-hw/src/core/include/spec/cortex_a9/timer.h b/repos/base-hw/src/core/include/spec/cortex_a9/timer.h index ad0c3146d..342a78e78 100644 --- a/repos/base-hw/src/core/include/spec/cortex_a9/timer.h +++ b/repos/base-hw/src/core/include/spec/cortex_a9/timer.h @@ -85,8 +85,36 @@ class Genode::Timer : public Mmio */ void start_one_shot(time_t const tics, unsigned const); - time_t tics_to_us(time_t const tics) const { - return (tics / TICS_PER_MS) * 1000; } + time_t tics_to_us(time_t const tics) const + { + /* + * If we would do the translation with one division and + * multiplication over the whole argument, we would loose + * microseconds granularity although the timer frequency would + * allow for such granularity. Thus, we treat the most significant + * half and the least significant half of the argument separate. + * Each half is shifted to the best bit position for the + * translation, then translated, and then shifted back. + */ + static_assert(TICS_PER_MS >= 1000, "Bad TICS_PER_MS value"); + enum { + TICS_WIDTH = sizeof(time_t) * 8, + TICS_HALF_WIDTH = TICS_WIDTH / 2, + + TICS_MSB_MASK = ~0UL << TICS_HALF_WIDTH, + TICS_LSB_MASK = ~0UL >> TICS_HALF_WIDTH, + + TICS_MSB_RSHIFT = 10, + TICS_LSB_LSHIFT = TICS_HALF_WIDTH - TICS_MSB_RSHIFT, + }; + time_t const tics_msb = (tics & TICS_MSB_MASK) >> TICS_MSB_RSHIFT; + time_t const tics_lsb = (tics & TICS_LSB_MASK) << TICS_LSB_LSHIFT; + + time_t const us_msb = ((tics_msb * 1000) / TICS_PER_MS) << TICS_MSB_RSHIFT; + time_t const us_lsb = ((tics_lsb * 1000) / TICS_PER_MS) >> TICS_LSB_LSHIFT; + + return us_msb | us_lsb; + } time_t us_to_tics(time_t const us) const { return (us / 1000) * TICS_PER_MS; }