FastLED  3.1
lib8tion.cpp
1 #define FASTLED_INTERNAL
2 #include <stdint.h>
3 #include "FastLED.h"
4 
5 FASTLED_NAMESPACE_BEGIN
6 
7 #define RAND16_SEED 1337
8 uint16_t rand16seed = RAND16_SEED;
9 
10 
11 // memset8, memcpy8, memmove8:
12 // optimized avr replacements for the standard "C" library
13 // routines memset, memcpy, and memmove.
14 //
15 // There are two techniques that make these routines
16 // faster than the standard avr-libc routines.
17 // First, the loops are unrolled 2X, meaning that
18 // the average loop overhead is cut in half.
19 // And second, the compare-and-branch at the bottom
20 // of each loop decrements the low byte of the
21 // counter, and if the carry is clear, it branches
22 // back up immediately. Only if the low byte math
23 // causes carry do we bother to decrement the high
24 // byte and check that result for carry as well.
25 // Results for a 100-byte buffer are 20-40% faster
26 // than standard avr-libc, at a cost of a few extra
27 // bytes of code.
28 
29 #if defined(__AVR__)
30 extern "C" {
31 //__attribute__ ((noinline))
32 void * memset8 ( void * ptr, uint8_t val, uint16_t num )
33 {
34  asm volatile(
35  " movw r26, %[ptr] \n\t"
36  " sbrs %A[num], 0 \n\t"
37  " rjmp Lseteven_%= \n\t"
38  " rjmp Lsetodd_%= \n\t"
39  "Lsetloop_%=: \n\t"
40  " st X+, %[val] \n\t"
41  "Lsetodd_%=: \n\t"
42  " st X+, %[val] \n\t"
43  "Lseteven_%=: \n\t"
44  " subi %A[num], 2 \n\t"
45  " brcc Lsetloop_%= \n\t"
46  " sbci %B[num], 0 \n\t"
47  " brcc Lsetloop_%= \n\t"
48  : [num] "+r" (num)
49  : [ptr] "r" (ptr),
50  [val] "r" (val)
51  : "memory"
52  );
53  return ptr;
54 }
55 
56 
57 
58 //__attribute__ ((noinline))
59 void * memcpy8 ( void * dst, const void* src, uint16_t num )
60 {
61  asm volatile(
62  " movw r30, %[src] \n\t"
63  " movw r26, %[dst] \n\t"
64  " sbrs %A[num], 0 \n\t"
65  " rjmp Lcpyeven_%= \n\t"
66  " rjmp Lcpyodd_%= \n\t"
67  "Lcpyloop_%=: \n\t"
68  " ld __tmp_reg__, Z+ \n\t"
69  " st X+, __tmp_reg__ \n\t"
70  "Lcpyodd_%=: \n\t"
71  " ld __tmp_reg__, Z+ \n\t"
72  " st X+, __tmp_reg__ \n\t"
73  "Lcpyeven_%=: \n\t"
74  " subi %A[num], 2 \n\t"
75  " brcc Lcpyloop_%= \n\t"
76  " sbci %B[num], 0 \n\t"
77  " brcc Lcpyloop_%= \n\t"
78  : [num] "+r" (num)
79  : [src] "r" (src),
80  [dst] "r" (dst)
81  : "memory"
82  );
83  return dst;
84 }
85 
86 //__attribute__ ((noinline))
87 void * memmove8 ( void * dst, const void* src, uint16_t num )
88 {
89  if( src > dst) {
90  // if src > dst then we can use the forward-stepping memcpy8
91  return memcpy8( dst, src, num);
92  } else {
93  // if src < dst then we have to step backward:
94  dst = (char*)dst + num;
95  src = (char*)src + num;
96  asm volatile(
97  " movw r30, %[src] \n\t"
98  " movw r26, %[dst] \n\t"
99  " sbrs %A[num], 0 \n\t"
100  " rjmp Lmoveven_%= \n\t"
101  " rjmp Lmovodd_%= \n\t"
102  "Lmovloop_%=: \n\t"
103  " ld __tmp_reg__, -Z \n\t"
104  " st -X, __tmp_reg__ \n\t"
105  "Lmovodd_%=: \n\t"
106  " ld __tmp_reg__, -Z \n\t"
107  " st -X, __tmp_reg__ \n\t"
108  "Lmoveven_%=: \n\t"
109  " subi %A[num], 2 \n\t"
110  " brcc Lmovloop_%= \n\t"
111  " sbci %B[num], 0 \n\t"
112  " brcc Lmovloop_%= \n\t"
113  : [num] "+r" (num)
114  : [src] "r" (src),
115  [dst] "r" (dst)
116  : "memory"
117  );
118  return dst;
119  }
120 }
121 
122 
123 } /* end extern "C" */
124 
125 #endif /* AVR */
126 
127 
128 
129 
130 #if 0
131 // TEST / VERIFICATION CODE ONLY BELOW THIS POINT
132 #include <Arduino.h>
133 #include "lib8tion.h"
134 
135 void test1abs( int8_t i)
136 {
137  Serial.print("abs("); Serial.print(i); Serial.print(") = ");
138  int8_t j = abs8(i);
139  Serial.print(j); Serial.println(" ");
140 }
141 
142 void testabs()
143 {
144  delay(5000);
145  for( int8_t q = -128; q != 127; q++) {
146  test1abs(q);
147  }
148  for(;;){};
149 }
150 
151 
152 void testmul8()
153 {
154  delay(5000);
155  byte r, c;
156 
157  Serial.println("mul8:");
158  for( r = 0; r <= 20; r += 1) {
159  Serial.print(r); Serial.print(" : ");
160  for( c = 0; c <= 20; c += 1) {
161  byte t;
162  t = mul8( r, c);
163  Serial.print(t); Serial.print(' ');
164  }
165  Serial.println(' ');
166  }
167  Serial.println("done.");
168  for(;;){};
169 }
170 
171 
172 void testscale8()
173 {
174  delay(5000);
175  byte r, c;
176 
177  Serial.println("scale8:");
178  for( r = 0; r <= 240; r += 10) {
179  Serial.print(r); Serial.print(" : ");
180  for( c = 0; c <= 240; c += 10) {
181  byte t;
182  t = scale8( r, c);
183  Serial.print(t); Serial.print(' ');
184  }
185  Serial.println(' ');
186  }
187 
188  Serial.println(' ');
189  Serial.println("scale8_video:");
190 
191  for( r = 0; r <= 100; r += 4) {
192  Serial.print(r); Serial.print(" : ");
193  for( c = 0; c <= 100; c += 4) {
194  byte t;
195  t = scale8_video( r, c);
196  Serial.print(t); Serial.print(' ');
197  }
198  Serial.println(' ');
199  }
200 
201  Serial.println("done.");
202  for(;;){};
203 }
204 
205 
206 
207 void testqadd8()
208 {
209  delay(5000);
210  byte r, c;
211  for( r = 0; r <= 240; r += 10) {
212  Serial.print(r); Serial.print(" : ");
213  for( c = 0; c <= 240; c += 10) {
214  byte t;
215  t = qadd8( r, c);
216  Serial.print(t); Serial.print(' ');
217  }
218  Serial.println(' ');
219  }
220  Serial.println("done.");
221  for(;;){};
222 }
223 
224 void testnscale8x3()
225 {
226  delay(5000);
227  byte r, g, b, sc;
228  for( byte z = 0; z < 10; z++) {
229  r = random8(); g = random8(); b = random8(); sc = random8();
230 
231  Serial.print("nscale8x3_video( ");
232  Serial.print(r); Serial.print(", ");
233  Serial.print(g); Serial.print(", ");
234  Serial.print(b); Serial.print(", ");
235  Serial.print(sc); Serial.print(") = [ ");
236 
237  nscale8x3_video( r, g, b, sc);
238 
239  Serial.print(r); Serial.print(", ");
240  Serial.print(g); Serial.print(", ");
241  Serial.print(b); Serial.print("]");
242 
243  Serial.println(' ');
244  }
245  Serial.println("done.");
246  for(;;){};
247 }
248 
249 #endif
250 
251 FASTLED_NAMESPACE_END
uint16_t rand16seed
random number seed
Definition: lib8tion.cpp:8
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 int8_t abs8(int8_t i)
take abs() of a signed 8-bit uint8_t
Definition: math8.h:354
LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video(uint8_t i, fract8 scale)
The "video" version of scale8 guarantees that the output will be only be zero if one or both of the i...
Definition: scale8.h:98
LIB8STATIC uint8_t random8()
Generate an 8-bit random number.
Definition: random8.h:19
LIB8STATIC void nscale8x3_video(uint8_t &r, uint8_t &g, uint8_t &b, fract8 scale)
scale three one byte values by a fourth one, which is treated as the numerator of a fraction whose de...
Definition: scale8.h:344
central include file for FastLED, defines the CFastLED class/object
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_ALWAYS_INLINE uint8_t scale8(uint8_t i, fract8 scale)
scale one byte by a second one, which is treated as the numerator of a fraction whose denominator is ...
Definition: scale8.h:20
Template class for represneting fractional ints.
Definition: lib8tion.h:754