FastLED  3.1
math8.h
1 #ifndef __INC_LIB8TION_MATH_H
2 #define __INC_LIB8TION_MATH_H
3 
5 
15 
16 
21 LIB8STATIC_ALWAYS_INLINE uint8_t qadd8( uint8_t i, uint8_t j)
22 {
23 #if QADD8_C == 1
24  unsigned int t = i + j;
25  if( t > 255) t = 255;
26  return t;
27 #elif QADD8_AVRASM == 1
28  asm volatile(
29  /* First, add j to i, conditioning the C flag */
30  "add %0, %1 \n\t"
31 
32  /* Now test the C flag.
33  If C is clear, we branch around a load of 0xFF into i.
34  If C is set, we go ahead and load 0xFF into i.
35  */
36  "brcc L_%= \n\t"
37  "ldi %0, 0xFF \n\t"
38  "L_%=: "
39  : "+a" (i)
40  : "a" (j) );
41  return i;
42 #elif QADD8_ARM_DSP_ASM == 1
43  asm volatile( "uqadd8 %0, %0, %1" : "+r" (i) : "r" (j));
44  return i;
45 #else
46 #error "No implementation for qadd8 available."
47 #endif
48 }
49 
54 LIB8STATIC_ALWAYS_INLINE int8_t qadd7( int8_t i, int8_t j)
55 {
56 #if QADD7_C == 1
57  int16_t t = i + j;
58  if( t > 127) t = 127;
59  return t;
60 #elif QADD7_AVRASM == 1
61  asm volatile(
62  /* First, add j to i, conditioning the V flag */
63  "add %0, %1 \n\t"
64 
65  /* Now test the V flag.
66  If V is clear, we branch around a load of 0x7F into i.
67  If V is set, we go ahead and load 0x7F into i.
68  */
69  "brvc L_%= \n\t"
70  "ldi %0, 0x7F \n\t"
71  "L_%=: "
72  : "+a" (i)
73  : "a" (j) );
74 
75  return i;
76 #elif QADD7_ARM_DSP_ASM == 1
77  asm volatile( "qadd8 %0, %0, %1" : "+r" (i) : "r" (j));
78  return i;
79 #else
80 #error "No implementation for qadd7 available."
81 #endif
82 }
83 
86 LIB8STATIC_ALWAYS_INLINE uint8_t qsub8( uint8_t i, uint8_t j)
87 {
88 #if QSUB8_C == 1
89  int t = i - j;
90  if( t < 0) t = 0;
91  return t;
92 #elif QSUB8_AVRASM == 1
93 
94  asm volatile(
95  /* First, subtract j from i, conditioning the C flag */
96  "sub %0, %1 \n\t"
97 
98  /* Now test the C flag.
99  If C is clear, we branch around a load of 0x00 into i.
100  If C is set, we go ahead and load 0x00 into i.
101  */
102  "brcc L_%= \n\t"
103  "ldi %0, 0x00 \n\t"
104  "L_%=: "
105  : "+a" (i)
106  : "a" (j) );
107 
108  return i;
109 #else
110 #error "No implementation for qsub8 available."
111 #endif
112 }
113 
115 LIB8STATIC_ALWAYS_INLINE uint8_t add8( uint8_t i, uint8_t j)
116 {
117 #if ADD8_C == 1
118  int t = i + j;
119  return t;
120 #elif ADD8_AVRASM == 1
121  // Add j to i, period.
122  asm volatile( "add %0, %1" : "+a" (i) : "a" (j));
123  return i;
124 #else
125 #error "No implementation for add8 available."
126 #endif
127 }
128 
129 
131 LIB8STATIC_ALWAYS_INLINE uint8_t sub8( uint8_t i, uint8_t j)
132 {
133 #if SUB8_C == 1
134  int t = i - j;
135  return t;
136 #elif SUB8_AVRASM == 1
137  // Subtract j from i, period.
138  asm volatile( "sub %0, %1" : "+a" (i) : "a" (j));
139  return i;
140 #else
141 #error "No implementation for sub8 available."
142 #endif
143 }
144 
148 LIB8STATIC_ALWAYS_INLINE uint8_t avg8( uint8_t i, uint8_t j)
149 {
150 #if AVG8_C == 1
151  return (i + j) >> 1;
152 #elif AVG8_AVRASM == 1
153  asm volatile(
154  /* First, add j to i, 9th bit overflows into C flag */
155  "add %0, %1 \n\t"
156  /* Divide by two, moving C flag into high 8th bit */
157  "ror %0 \n\t"
158  : "+a" (i)
159  : "a" (j) );
160  return i;
161 #else
162 #error "No implementation for avg8 available."
163 #endif
164 }
165 
169 LIB8STATIC_ALWAYS_INLINE uint16_t avg16( uint16_t i, uint16_t j)
170 {
171 #if AVG16_C == 1
172  return (uint32_t)((uint32_t)(i) + (uint32_t)(j)) >> 1;
173 #elif AVG16_AVRASM == 1
174  asm volatile(
175  /* First, add jLo (heh) to iLo, 9th bit overflows into C flag */
176  "add %A[i], %A[j] \n\t"
177  /* Now, add C + jHi to iHi, 17th bit overflows into C flag */
178  "adc %B[i], %B[j] \n\t"
179  /* Divide iHi by two, moving C flag into high 16th bit, old 9th bit now in C */
180  "ror %B[i] \n\t"
181  /* Divide iLo by two, moving C flag into high 8th bit */
182  "ror %A[i] \n\t"
183  : [i] "+a" (i)
184  : [j] "a" (j) );
185  return i;
186 #else
187 #error "No implementation for avg16 available."
188 #endif
189 }
190 
191 
196 LIB8STATIC_ALWAYS_INLINE int8_t avg7( int8_t i, int8_t j)
197 {
198 #if AVG7_C == 1
199  return ((i + j) >> 1) + (i & 0x1);
200 #elif AVG7_AVRASM == 1
201  asm volatile(
202  "asr %1 \n\t"
203  "asr %0 \n\t"
204  "adc %0, %1 \n\t"
205  : "+a" (i)
206  : "a" (j) );
207  return i;
208 #else
209 #error "No implementation for avg7 available."
210 #endif
211 }
212 
217 LIB8STATIC_ALWAYS_INLINE int16_t avg15( int16_t i, int16_t j)
218 {
219 #if AVG15_C == 1
220  return ((int32_t)((int32_t)(i) + (int32_t)(j)) >> 1) + (i & 0x1);
221 #elif AVG15_AVRASM == 1
222  asm volatile(
223  /* first divide j by 2, throwing away lowest bit */
224  "asr %B[j] \n\t"
225  "ror %A[j] \n\t"
226  /* now divide i by 2, with lowest bit going into C */
227  "asr %B[i] \n\t"
228  "ror %A[i] \n\t"
229  /* add j + C to i */
230  "adc %A[i], %A[j] \n\t"
231  "adc %B[i], %B[j] \n\t"
232  : [i] "+a" (i)
233  : [j] "a" (j) );
234  return i;
235 #else
236 #error "No implementation for avg15 available."
237 #endif
238 }
239 
240 
249 LIB8STATIC_ALWAYS_INLINE uint8_t mod8( uint8_t a, uint8_t m)
250 {
251 #if defined(__AVR__)
252  asm volatile (
253  "L_%=: sub %[a],%[m] \n\t"
254  " brcc L_%= \n\t"
255  " add %[a],%[m] \n\t"
256  : [a] "+r" (a)
257  : [m] "r" (m)
258  );
259 #else
260  while( a >= m) a -= m;
261 #endif
262  return a;
263 }
264 
276 LIB8STATIC uint8_t addmod8( uint8_t a, uint8_t b, uint8_t m)
277 {
278 #if defined(__AVR__)
279  asm volatile (
280  " add %[a],%[b] \n\t"
281  "L_%=: sub %[a],%[m] \n\t"
282  " brcc L_%= \n\t"
283  " add %[a],%[m] \n\t"
284  : [a] "+r" (a)
285  : [b] "r" (b), [m] "r" (m)
286  );
287 #else
288  a += b;
289  while( a >= m) a -= m;
290 #endif
291  return a;
292 }
293 
295 LIB8STATIC_ALWAYS_INLINE uint8_t mul8( uint8_t i, uint8_t j)
296 {
297 #if MUL8_C == 1
298  return ((int)i * (int)(j) ) & 0xFF;
299 #elif MUL8_AVRASM == 1
300  asm volatile(
301  /* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
302  "mul %0, %1 \n\t"
303  /* Extract the LOW 8-bits (r0) */
304  "mov %0, r0 \n\t"
305  /* Restore r1 to "0"; it's expected to always be that */
306  "clr __zero_reg__ \n\t"
307  : "+a" (i)
308  : "a" (j)
309  : "r0", "r1");
310 
311  return i;
312 #else
313 #error "No implementation for mul8 available."
314 #endif
315 }
316 
317 
320 LIB8STATIC_ALWAYS_INLINE uint8_t qmul8( uint8_t i, uint8_t j)
321 {
322 #if QMUL8_C == 1
323  int p = ((int)i * (int)(j) );
324  if( p > 255) p = 255;
325  return p;
326 #elif QMUL8_AVRASM == 1
327  asm volatile(
328  /* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
329  " mul %0, %1 \n\t"
330  /* If high byte of result is zero, all is well. */
331  " tst r1 \n\t"
332  " breq Lnospill_%= \n\t"
333  /* If high byte of result > 0, saturate low byte to 0xFF */
334  " ldi %0,0xFF \n\t"
335  " rjmp Ldone_%= \n\t"
336  "Lnospill_%=: \n\t"
337  /* Extract the LOW 8-bits (r0) */
338  " mov %0, r0 \n\t"
339  "Ldone_%=: \n\t"
340  /* Restore r1 to "0"; it's expected to always be that */
341  " clr __zero_reg__ \n\t"
342  : "+a" (i)
343  : "a" (j)
344  : "r0", "r1");
345 
346  return i;
347 #else
348 #error "No implementation for qmul8 available."
349 #endif
350 }
351 
352 
354 LIB8STATIC_ALWAYS_INLINE int8_t abs8( int8_t i)
355 {
356 #if ABS8_C == 1
357  if( i < 0) i = -i;
358  return i;
359 #elif ABS8_AVRASM == 1
360 
361 
362  asm volatile(
363  /* First, check the high bit, and prepare to skip if it's clear */
364  "sbrc %0, 7 \n"
365 
366  /* Negate the value */
367  "neg %0 \n"
368 
369  : "+r" (i) : "r" (i) );
370  return i;
371 #else
372 #error "No implementation for abs8 available."
373 #endif
374 }
375 
379 LIB8STATIC uint8_t sqrt16(uint16_t x)
380 {
381  if( x <= 1) {
382  return x;
383  }
384 
385  uint8_t low = 1; // lower bound
386  uint8_t hi, mid;
387 
388  if( x > 7904) {
389  hi = 255;
390  } else {
391  hi = (x >> 5) + 8; // initial estimate for upper bound
392  }
393 
394  do {
395  mid = (low + hi) >> 1;
396  if ((uint16_t)(mid * mid) > x) {
397  hi = mid - 1;
398  } else {
399  if( mid == 255) {
400  return 255;
401  }
402  low = mid + 1;
403  }
404  } while (hi >= low);
405 
406  return low - 1;
407 }
408 
410 #endif
LIB8STATIC_ALWAYS_INLINE uint8_t mul8(uint8_t i, uint8_t j)
8x8 bit multiplication, with 8 bit result
Definition: math8.h:295
LIB8STATIC_ALWAYS_INLINE uint8_t sub8(uint8_t i, uint8_t j)
subtract one byte from another, 8-bit result
Definition: math8.h:131
LIB8STATIC_ALWAYS_INLINE uint8_t qsub8(uint8_t i, uint8_t j)
subtract one byte from another, saturating at 0x00
Definition: math8.h:86
LIB8STATIC_ALWAYS_INLINE uint8_t avg8(uint8_t i, uint8_t j)
Calculate an integer average of two unsigned 8-bit integer values (uint8_t).
Definition: math8.h:148
LIB8STATIC_ALWAYS_INLINE uint8_t qmul8(uint8_t i, uint8_t j)
saturating 8x8 bit multiplication, with 8 bit result
Definition: math8.h:320
LIB8STATIC_ALWAYS_INLINE int16_t avg15(int16_t i, int16_t j)
Calculate an integer average of two signed 15-bit integers (int16_t) If the first argument is even...
Definition: math8.h:217
LIB8STATIC uint8_t addmod8(uint8_t a, uint8_t b, uint8_t m)
Add two numbers, and calculate the modulo of the sum and a third number, M.
Definition: math8.h:276
LIB8STATIC_ALWAYS_INLINE int8_t qadd7(int8_t i, int8_t j)
Add one byte to another, saturating at 0x7F.
Definition: math8.h:54
LIB8STATIC_ALWAYS_INLINE int8_t abs8(int8_t i)
take abs() of a signed 8-bit uint8_t
Definition: math8.h:354
LIB8STATIC_ALWAYS_INLINE int8_t avg7(int8_t i, int8_t j)
Calculate an integer average of two signed 7-bit integers (int8_t) If the first argument is even...
Definition: math8.h:196
LIB8STATIC_ALWAYS_INLINE uint8_t mod8(uint8_t a, uint8_t m)
Calculate the remainder of one unsigned 8-bit value divided by anoter, aka A % M. ...
Definition: math8.h:249
LIB8STATIC_ALWAYS_INLINE uint16_t avg16(uint16_t i, uint16_t j)
Calculate an integer average of two unsigned 16-bit integer values (uint16_t).
Definition: math8.h:169
LIB8STATIC_ALWAYS_INLINE uint8_t qadd8(uint8_t i, uint8_t j)
add one byte to another, saturating at 0xFF
Definition: math8.h:21
LIB8STATIC uint8_t sqrt16(uint16_t x)
square root for 16-bit integers About three times faster and five times smaller than Arduino's genera...
Definition: math8.h:379
LIB8STATIC_ALWAYS_INLINE uint8_t add8(uint8_t i, uint8_t j)
add one byte to another, with one byte result
Definition: math8.h:115