diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2017-03-24 23:17:23 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2017-03-26 22:45:58 -0400 |
commit | 4dfa6c6ee454d14a006033e218acbb7fa9ced8bd (patch) | |
tree | 8d8708a7d2d6b9d63cfcd54fe60859f900117382 /src/avr/timer.c | |
parent | 60e488eb177a35084669cb85d81131ce95eac959 (diff) | |
download | kutter-4dfa6c6ee454d14a006033e218acbb7fa9ced8bd.tar.gz kutter-4dfa6c6ee454d14a006033e218acbb7fa9ced8bd.tar.xz kutter-4dfa6c6ee454d14a006033e218acbb7fa9ced8bd.zip |
avr: Introduce optimized timer_is_before()
Provide hand-coded assembler for timer_is_before() on AVR as that code
is used frequently in the time-critical timer dispatch loop and gcc
doesn't do a good job at compiling that comparison code. Remove the
no longer needed waketime+1 hack from reschedule_timer().
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/avr/timer.c')
-rw-r--r-- | src/avr/timer.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/src/avr/timer.c b/src/avr/timer.c index e96b88bf..f1fbd284 100644 --- a/src/avr/timer.c +++ b/src/avr/timer.c @@ -25,13 +25,29 @@ timer_from_us(uint32_t us) return us * (F_CPU / 1000000); } +union u32_u { + struct { uint8_t b0, b1, b2, b3; }; + struct { uint16_t lo, hi; }; + uint32_t val; +}; + // Return true if time1 is before time2. Always use this function to // compare times as regular C comparisons can fail if the counter // rolls over. -uint8_t +uint8_t __always_inline timer_is_before(uint32_t time1, uint32_t time2) { - return (int32_t)(time1 - time2) < 0; + // This asm is equivalent to: + // return (int32_t)(time1 - time2) < 0; + // But gcc doesn't do a good job with the above, so it's hand coded. + union u32_u utime1 = { .val = time1 }; + uint8_t f = utime1.b3; + asm(" cp %A1, %A2\n" + " cpc %B1, %B2\n" + " cpc %C1, %C2\n" + " sbc %0, %D2" + : "+r"(f) : "r"(time1), "r"(time2)); + return (int8_t)f < 0; } static inline uint16_t @@ -99,11 +115,8 @@ static uint16_t timer_high; uint32_t timer_read_time(void) { - union u32_u16_u { - struct { uint16_t lo, hi; }; - uint32_t val; - } calc; irqstatus_t flag = irq_save(); + union u32_u calc; calc.val = timer_get(); calc.hi = timer_high; if (!(TIFR1 & (1<<TOV1))) { |