#ifndef __INC_LIB8TION_MATH_H
#define __INC_LIB8TION_MATH_H
#include "scale8.h"
LIB8STATIC_ALWAYS_INLINE uint8_t qadd8( uint8_t i, uint8_t j)
{
#if QADD8_C == 1
uint16_t t = i + j;
if (t > 255) t = 255;
return t;
#elif QADD8_AVRASM == 1
asm volatile(
"add %0, %1 \n\t"
"brcc L_%= \n\t"
"ldi %0, 0xFF \n\t"
"L_%=: "
: "+a" (i)
: "a" (j) );
return i;
#elif QADD8_ARM_DSP_ASM == 1
asm volatile( "uqadd8 %0, %0, %1" : "+r" (i) : "r" (j));
return i;
#else
#error "No implementation for qadd8 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE int8_t qadd7( int8_t i, int8_t j)
{
#if QADD7_C == 1
int16_t t = i + j;
if (t > 127) t = 127;
return t;
#elif QADD7_AVRASM == 1
asm volatile(
"add %0, %1 \n\t"
"brvc L_%= \n\t"
"ldi %0, 0x7F \n\t"
"L_%=: "
: "+a" (i)
: "a" (j) );
return i;
#elif QADD7_ARM_DSP_ASM == 1
asm volatile( "qadd8 %0, %0, %1" : "+r" (i) : "r" (j));
return i;
#else
#error "No implementation for qadd7 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint8_t qsub8( uint8_t i, uint8_t j)
{
#if QSUB8_C == 1
int16_t t = i - j;
if (t < 0) t = 0;
return t;
#elif QSUB8_AVRASM == 1
asm volatile(
"sub %0, %1 \n\t"
"brcc L_%= \n\t"
"ldi %0, 0x00 \n\t"
"L_%=: "
: "+a" (i)
: "a" (j) );
return i;
#else
#error "No implementation for qsub8 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint8_t add8( uint8_t i, uint8_t j)
{
#if ADD8_C == 1
uint16_t t = i + j;
return t;
#elif ADD8_AVRASM == 1
asm volatile( "add %0, %1" : "+a" (i) : "a" (j));
return i;
#else
#error "No implementation for add8 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint16_t add8to16( uint8_t i, uint16_t j)
{
#if ADD8_C == 1
uint16_t t = i + j;
return t;
#elif ADD8_AVRASM == 1
asm volatile( "add %A[j], %[i] \n\t"
"adc %B[j], __zero_reg__ \n\t"
: [j] "+a" (j)
: [i] "a" (i)
);
return i;
#else
#error "No implementation for add8to16 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint8_t sub8( uint8_t i, uint8_t j)
{
#if SUB8_C == 1
int16_t t = i - j;
return t;
#elif SUB8_AVRASM == 1
asm volatile( "sub %0, %1" : "+a" (i) : "a" (j));
return i;
#else
#error "No implementation for sub8 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint8_t avg8( uint8_t i, uint8_t j)
{
#if AVG8_C == 1
return (i + j) >> 1;
#elif AVG8_AVRASM == 1
asm volatile(
"add %0, %1 \n\t"
"ror %0 \n\t"
: "+a" (i)
: "a" (j) );
return i;
#else
#error "No implementation for avg8 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint16_t avg16( uint16_t i, uint16_t j)
{
#if AVG16_C == 1
return (uint32_t)((uint32_t)(i) + (uint32_t)(j)) >> 1;
#elif AVG16_AVRASM == 1
asm volatile(
"add %A[i], %A[j] \n\t"
"adc %B[i], %B[j] \n\t"
"ror %B[i] \n\t"
"ror %A[i] \n\t"
: [i] "+a" (i)
: [j] "a" (j) );
return i;
#else
#error "No implementation for avg16 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE int8_t avg7( int8_t i, int8_t j)
{
#if AVG7_C == 1
return ((i + j) >> 1) + (i & 0x1);
#elif AVG7_AVRASM == 1
asm volatile(
"asr %1 \n\t"
"asr %0 \n\t"
"adc %0, %1 \n\t"
: "+a" (i)
: "a" (j) );
return i;
#else
#error "No implementation for avg7 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE int16_t avg15( int16_t i, int16_t j)
{
#if AVG15_C == 1
return ((int32_t)((int32_t)(i) + (int32_t)(j)) >> 1) + (i & 0x1);
#elif AVG15_AVRASM == 1
asm volatile(
"asr %B[j] \n\t"
"ror %A[j] \n\t"
"asr %B[i] \n\t"
"ror %A[i] \n\t"
"adc %A[i], %A[j] \n\t"
"adc %B[i], %B[j] \n\t"
: [i] "+a" (i)
: [j] "a" (j) );
return i;
#else
#error "No implementation for avg15 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint8_t mod8( uint8_t a, uint8_t m)
{
#if defined(__AVR__)
asm volatile (
"L_%=: sub %[a],%[m] \n\t"
" brcc L_%= \n\t"
" add %[a],%[m] \n\t"
: [a] "+r" (a)
: [m] "r" (m)
);
#else
while( a >= m) a -= m;
#endif
return a;
}
LIB8STATIC uint8_t addmod8( uint8_t a, uint8_t b, uint8_t m)
{
#if defined(__AVR__)
asm volatile (
" add %[a],%[b] \n\t"
"L_%=: sub %[a],%[m] \n\t"
" brcc L_%= \n\t"
" add %[a],%[m] \n\t"
: [a] "+r" (a)
: [b] "r" (b), [m] "r" (m)
);
#else
a += b;
while( a >= m) a -= m;
#endif
return a;
}
LIB8STATIC uint8_t submod8( uint8_t a, uint8_t b, uint8_t m)
{
#if defined(__AVR__)
asm volatile (
" sub %[a],%[b] \n\t"
"L_%=: sub %[a],%[m] \n\t"
" brcc L_%= \n\t"
" add %[a],%[m] \n\t"
: [a] "+r" (a)
: [b] "r" (b), [m] "r" (m)
);
#else
a -= b;
while( a >= m) a -= m;
#endif
return a;
}
LIB8STATIC_ALWAYS_INLINE uint8_t mul8( uint8_t i, uint8_t j)
{
#if MUL8_C == 1
return ((uint16_t)i * (uint16_t)(j) ) & 0xFF;
#elif MUL8_AVRASM == 1
asm volatile(
"mul %0, %1 \n\t"
"mov %0, r0 \n\t"
"clr __zero_reg__ \n\t"
: "+a" (i)
: "a" (j)
: "r0", "r1");
return i;
#else
#error "No implementation for mul8 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE uint8_t qmul8( uint8_t i, uint8_t j)
{
#if QMUL8_C == 1
int p = ((uint16_t)i * (uint16_t)(j) );
if( p > 255) p = 255;
return p;
#elif QMUL8_AVRASM == 1
asm volatile(
" mul %0, %1 \n\t"
" tst r1 \n\t"
" breq Lnospill_%= \n\t"
" ldi %0,0xFF \n\t"
" rjmp Ldone_%= \n\t"
"Lnospill_%=: \n\t"
" mov %0, r0 \n\t"
"Ldone_%=: \n\t"
" clr __zero_reg__ \n\t"
: "+a" (i)
: "a" (j)
: "r0", "r1");
return i;
#else
#error "No implementation for qmul8 available."
#endif
}
LIB8STATIC_ALWAYS_INLINE int8_t abs8( int8_t i)
{
#if ABS8_C == 1
if( i < 0) i = -i;
return i;
#elif ABS8_AVRASM == 1
asm volatile(
"sbrc %0, 7 \n"
"neg %0 \n"
: "+r" (i) : "r" (i) );
return i;
#else
#error "No implementation for abs8 available."
#endif
}
LIB8STATIC uint8_t sqrt16(uint16_t x)
{
if( x <= 1) {
return x;
}
uint8_t low = 1; uint8_t hi, mid;
if( x > 7904) {
hi = 255;
} else {
hi = (x >> 5) + 8; }
do {
mid = (low + hi) >> 1;
if ((uint16_t)(mid * mid) > x) {
hi = mid - 1;
} else {
if( mid == 255) {
return 255;
}
low = mid + 1;
}
} while (hi >= low);
return low - 1;
}
#if (FASTLED_BLEND_FIXED == 1)
LIB8STATIC uint8_t blend8( uint8_t a, uint8_t b, uint8_t amountOfB)
{
#if BLEND8_C == 1
uint16_t partial;
uint8_t result;
uint8_t amountOfA = 255 - amountOfB;
partial = (a * amountOfA);
#if (FASTLED_SCALE8_FIXED == 1)
partial += a;
#endif
partial += (b * amountOfB);
#if (FASTLED_SCALE8_FIXED == 1)
partial += b;
#endif
result = partial >> 8;
return result;
#elif BLEND8_AVRASM == 1
uint16_t partial;
uint8_t result;
asm volatile (
" mul %[b], %[amountOfB] \n\t"
" movw %A[partial], r0 \n\t"
" com %[amountOfB] \n\t"
" mul %[a], %[amountOfB] \n\t"
" add %A[partial], r0 \n\t"
" adc %B[partial], r1 \n\t"
" clr __zero_reg__ \n\t"
#if (FASTLED_SCALE8_FIXED == 1)
" add %A[partial], %[a] \n\t"
" adc %B[partial], __zero_reg__ \n\t"
" add %A[partial], %[b] \n\t"
" adc %B[partial], __zero_reg__ \n\t"
#endif
: [partial] "=r" (partial),
[amountOfB] "+a" (amountOfB)
: [a] "a" (a),
[b] "a" (b)
: "r0", "r1"
);
result = partial >> 8;
return result;
#else
#error "No implementation for blend8 available."
#endif
}
#else
LIB8STATIC uint8_t blend8( uint8_t a, uint8_t b, uint8_t amountOfB)
{
uint8_t result;
uint8_t amountOfA = 255 - amountOfB;
result = scale8_LEAVING_R1_DIRTY( a, amountOfA)
+ scale8_LEAVING_R1_DIRTY( b, amountOfB);
cleanup_R1();
return result;
}
#endif
#endif