FastLED 3.10.6
Loading...
Searching...
No Matches
wave8.cpp.hpp
Go to the documentation of this file.
1
8
9// IWYU pragma: private
10
13#include "fl/stl/bit_cast.h"
15#include "fl/stl/isr/memcpy.h"
16
18
19namespace fl {
20
21namespace detail {
22
25 const Wave8BitExpansionLut& lut,
26 Wave8Byte* output) FL_NO_EXCEPT {
27 const Wave8Bit* high_nibble_data = lut.lut[(byte_value >> 4) & 0xF];
28 isr::memcpy_32(fl::bit_cast_ptr<u32>(&output->symbols[0]),
29 fl::bit_cast_ptr<const u32>(high_nibble_data),
30 1);
31
32 const Wave8Bit* low_nibble_data = lut.lut[byte_value & 0xF];
33 isr::memcpy_32(fl::bit_cast_ptr<u32>(&output->symbols[4]),
34 fl::bit_cast_ptr<const u32>(low_nibble_data),
35 1);
36}
37
39void wave8_expand_byte(u8 byte_value,
40 const Wave8ByteExpansionLut& lut,
41 Wave8Byte* output) FL_NO_EXCEPT {
43 fl::bit_cast_ptr<const u32>(&lut.lut[byte_value]),
44 2);
45}
46
48void wave8_transpose_2(const Wave8Byte lane_waves[2],
49 u8 output[2 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
50 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
51 u16 interleaved = 0;
52 FL_WAVE8_SPREAD_TO_16(lane_waves[0].symbols[symbol_idx].data,
53 lane_waves[1].symbols[symbol_idx].data,
54 interleaved);
55
56 output[symbol_idx * 2] = (u8)(interleaved >> 8);
57 output[symbol_idx * 2 + 1] = (u8)(interleaved & 0xFF);
58 }
59}
60
62void wave8_transpose_4(const Wave8Byte lane_waves[4],
63 u8 output[4 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
64 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
65 u8 l0 = lane_waves[0].symbols[symbol_idx].data;
66 u8 l1 = lane_waves[1].symbols[symbol_idx].data;
67 u8 l2 = lane_waves[2].symbols[symbol_idx].data;
68 u8 l3 = lane_waves[3].symbols[symbol_idx].data;
69
70 output[symbol_idx * 4 + 0] =
71 ((l3 >> 7) & 1) << 7 |
72 ((l2 >> 7) & 1) << 6 |
73 ((l1 >> 7) & 1) << 5 |
74 ((l0 >> 7) & 1) << 4 |
75 ((l3 >> 6) & 1) << 3 |
76 ((l2 >> 6) & 1) << 2 |
77 ((l1 >> 6) & 1) << 1 |
78 ((l0 >> 6) & 1);
79
80 output[symbol_idx * 4 + 1] =
81 ((l3 >> 5) & 1) << 7 |
82 ((l2 >> 5) & 1) << 6 |
83 ((l1 >> 5) & 1) << 5 |
84 ((l0 >> 5) & 1) << 4 |
85 ((l3 >> 4) & 1) << 3 |
86 ((l2 >> 4) & 1) << 2 |
87 ((l1 >> 4) & 1) << 1 |
88 ((l0 >> 4) & 1);
89
90 output[symbol_idx * 4 + 2] =
91 ((l3 >> 3) & 1) << 7 |
92 ((l2 >> 3) & 1) << 6 |
93 ((l1 >> 3) & 1) << 5 |
94 ((l0 >> 3) & 1) << 4 |
95 ((l3 >> 2) & 1) << 3 |
96 ((l2 >> 2) & 1) << 2 |
97 ((l1 >> 2) & 1) << 1 |
98 ((l0 >> 2) & 1);
99
100 output[symbol_idx * 4 + 3] =
101 ((l3 >> 1) & 1) << 7 |
102 ((l2 >> 1) & 1) << 6 |
103 ((l1 >> 1) & 1) << 5 |
104 ((l0 >> 1) & 1) << 4 |
105 ((l3 >> 0) & 1) << 3 |
106 ((l2 >> 0) & 1) << 2 |
107 ((l1 >> 0) & 1) << 1 |
108 ((l0 >> 0) & 1);
109 }
110}
111
113void wave8_transpose_8(const Wave8Byte lane_waves[8],
114 u8 output[8 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
115 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
116 u8 l[8];
117 for (int lane = 0; lane < 8; lane++) {
118 l[lane] = lane_waves[lane].symbols[symbol_idx].data;
119 }
120 spread_transpose8_symbol(l, output + symbol_idx * 8);
121 }
122}
123
125void wave8_transpose_16(const Wave8Byte lane_waves[16],
126 u8 output[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
127 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
128 u8 l[16];
129 for (int lane = 0; lane < 16; lane++) {
130 l[lane] = lane_waves[lane].symbols[symbol_idx].data;
131 }
132 spread_transpose16_symbol(l, output + symbol_idx * 16);
133 }
134}
135
137void wave8_transpose_16x2_pipe2(const Wave8Byte lane_waves_a[16],
138 const Wave8Byte lane_waves_b[16],
139 u8 output_a[16 * sizeof(Wave8Byte)],
140 u8 output_b[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
141 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
142 u8 la[16];
143 u8 lb[16];
144 for (int lane = 0; lane < 16; lane++) {
145 la[lane] = lane_waves_a[lane].symbols[symbol_idx].data;
146 lb[lane] = lane_waves_b[lane].symbols[symbol_idx].data;
147 }
148 spread_transpose16_symbol(la, output_a + symbol_idx * 16);
149 spread_transpose16_symbol(lb, output_b + symbol_idx * 16);
150 }
151}
152
154void wave8_transpose_16x4_pipe4(const Wave8Byte lane_waves_a[16],
155 const Wave8Byte lane_waves_b[16],
156 const Wave8Byte lane_waves_c[16],
157 const Wave8Byte lane_waves_d[16],
158 u8 output_a[16 * sizeof(Wave8Byte)],
159 u8 output_b[16 * sizeof(Wave8Byte)],
160 u8 output_c[16 * sizeof(Wave8Byte)],
161 u8 output_d[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
162 for (int symbol_idx = 0; symbol_idx < 8; symbol_idx++) {
163 u8 la[16];
164 u8 lb[16];
165 u8 lc[16];
166 u8 ld[16];
167 for (int lane = 0; lane < 16; lane++) {
168 la[lane] = lane_waves_a[lane].symbols[symbol_idx].data;
169 lb[lane] = lane_waves_b[lane].symbols[symbol_idx].data;
170 lc[lane] = lane_waves_c[lane].symbols[symbol_idx].data;
171 ld[lane] = lane_waves_d[lane].symbols[symbol_idx].data;
172 }
173 spread_transpose16_symbol(la, output_a + symbol_idx * 16);
174 spread_transpose16_symbol(lb, output_b + symbol_idx * 16);
175 spread_transpose16_symbol(lc, output_c + symbol_idx * 16);
176 spread_transpose16_symbol(ld, output_d + symbol_idx * 16);
177 }
178}
179
181void wave8_transpose_16_bf1(const u8 lanes[16],
182 u8 W0, u8 W1,
183 u8 output[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
184 u8 d_mask[8];
185 u8 m0_mask[8];
186 const u8 D_byte = W0 ^ W1;
187 for (int p = 0; p < 8; ++p) {
188 const int shift = 7 - p;
189 d_mask[p] = ((D_byte >> shift) & 1) ? 0xFFu : 0x00u;
190 m0_mask[p] = ((W0 >> shift) & 1) ? 0xFFu : 0x00u;
191 }
192 u8 cols[16];
193 spread_transpose16_symbol(lanes, cols);
194 for (int s = 0; s < 8; ++s) {
195 const u8 col_lo = cols[2 * s + 0];
196 const u8 col_hi = cols[2 * s + 1];
197 for (int p = 0; p < 8; ++p) {
198 output[s * 16 + p * 2 + 0] = m0_mask[p] ^ (col_lo & d_mask[p]);
199 output[s * 16 + p * 2 + 1] = m0_mask[p] ^ (col_hi & d_mask[p]);
200 }
201 }
202}
203
205void wave8_transpose_8_bf1(const u8 lanes[8],
206 u8 W0, u8 W1,
207 u8 output[8 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
208 u8 d_mask[8];
209 u8 m0_mask[8];
210 const u8 D_byte = W0 ^ W1;
211 for (int p = 0; p < 8; ++p) {
212 const int shift = 7 - p;
213 d_mask[p] = ((D_byte >> shift) & 1) ? 0xFFu : 0x00u;
214 m0_mask[p] = ((W0 >> shift) & 1) ? 0xFFu : 0x00u;
215 }
216 u8 cols[8];
217 spread_transpose8_symbol(lanes, cols);
218 for (int s = 0; s < 8; ++s) {
219 const u8 col = cols[s];
220 for (int p = 0; p < 8; ++p) {
221 output[s * 8 + p] = m0_mask[p] ^ (col & d_mask[p]);
222 }
223 }
224}
225
227void wave8_transpose_4_bf1(const u8 lanes[4],
228 u8 W0, u8 W1,
229 u8 output[4 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
230 u8 d_mask[8];
231 u8 m0_mask[8];
232 const u8 D_byte = W0 ^ W1;
233 for (int p = 0; p < 8; ++p) {
234 const int shift = 7 - p;
235 d_mask[p] = ((D_byte >> shift) & 1) ? 0xFFu : 0x00u;
236 m0_mask[p] = ((W0 >> shift) & 1) ? 0xFFu : 0x00u;
237 }
238 const u32 aLo = spreadA(lanes[0]) | (spreadA(lanes[1]) << 1)
239 | (spreadA(lanes[2]) << 2) | (spreadA(lanes[3]) << 3);
240 const u32 bLo = spreadB(lanes[0]) | (spreadB(lanes[1]) << 1)
241 | (spreadB(lanes[2]) << 2) | (spreadB(lanes[3]) << 3);
242 u8 cols[8];
243 cols[0] = static_cast<u8>(aLo);
244 cols[1] = static_cast<u8>(aLo >> 8);
245 cols[2] = static_cast<u8>(aLo >> 16);
246 cols[3] = static_cast<u8>(aLo >> 24);
247 cols[4] = static_cast<u8>(bLo);
248 cols[5] = static_cast<u8>(bLo >> 8);
249 cols[6] = static_cast<u8>(bLo >> 16);
250 cols[7] = static_cast<u8>(bLo >> 24);
251 for (int s = 0; s < 8; ++s) {
252 const u8 col = cols[s];
253 for (int k = 0; k < 4; ++k) {
254 const int p_hi = 2 * k;
255 const int p_lo = 2 * k + 1;
256 const u8 hi = static_cast<u8>((m0_mask[p_hi] & 0xF0u) ^ ((col << 4) & d_mask[p_hi]));
257 const u8 lo = static_cast<u8>((m0_mask[p_lo] & 0x0Fu) ^ (col & d_mask[p_lo]));
258 output[s * 4 + k] = static_cast<u8>(hi | lo);
259 }
260 }
261}
262
264void wave8_transpose_2_bf1(const u8 lanes[2],
265 u8 W0, u8 W1,
266 u8 output[2 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
267 u8 d_mask[8];
268 u8 m0_mask[8];
269 const u8 D_byte = W0 ^ W1;
270 for (int p = 0; p < 8; ++p) {
271 const int shift = 7 - p;
272 d_mask[p] = ((D_byte >> shift) & 1) ? 0xFFu : 0x00u;
273 m0_mask[p] = ((W0 >> shift) & 1) ? 0xFFu : 0x00u;
274 }
275 for (int s = 0; s < 8; ++s) {
276 const int bit_idx = 7 - s;
277 const u8 b0 = static_cast<u8>((lanes[0] >> bit_idx) & 1u);
278 const u8 b1 = static_cast<u8>((lanes[1] >> bit_idx) & 1u);
279 u8 byte_hi = 0;
280 u8 byte_lo = 0;
281 for (int q = 0; q < 4; ++q) {
282 const int p_hi = 3 - q;
283 const int p_lo = 7 - q;
284 const u8 m0_p_hi = static_cast<u8>(m0_mask[p_hi] & 1u);
285 const u8 d_p_hi = static_cast<u8>(d_mask[p_hi] & 1u);
286 const u8 m0_p_lo = static_cast<u8>(m0_mask[p_lo] & 1u);
287 const u8 d_p_lo = static_cast<u8>(d_mask[p_lo] & 1u);
288 const u8 v0_hi = static_cast<u8>(m0_p_hi ^ (b0 & d_p_hi));
289 const u8 v1_hi = static_cast<u8>(m0_p_hi ^ (b1 & d_p_hi));
290 const u8 v0_lo = static_cast<u8>(m0_p_lo ^ (b0 & d_p_lo));
291 const u8 v1_lo = static_cast<u8>(m0_p_lo ^ (b1 & d_p_lo));
292 byte_hi |= static_cast<u8>((v1_hi << (2 * q)) | (v0_hi << (2 * q + 1)));
293 byte_lo |= static_cast<u8>((v1_lo << (2 * q)) | (v0_lo << (2 * q + 1)));
294 }
295 output[s * 2 + 0] = byte_hi;
296 output[s * 2 + 1] = byte_lo;
297 }
298}
299
301void wave8_transpose_16x4_bf1_pipe4(const u8 lanes_a[16],
302 const u8 lanes_b[16],
303 const u8 lanes_c[16],
304 const u8 lanes_d[16],
305 u8 W0, u8 W1,
306 u8 output_a[16 * sizeof(Wave8Byte)],
307 u8 output_b[16 * sizeof(Wave8Byte)],
308 u8 output_c[16 * sizeof(Wave8Byte)],
309 u8 output_d[16 * sizeof(Wave8Byte)]) FL_NO_EXCEPT {
310 u8 d_mask[8];
311 u8 m0_mask[8];
312 const u8 D_byte = W0 ^ W1;
313 for (int p = 0; p < 8; ++p) {
314 const int shift = 7 - p;
315 d_mask[p] = ((D_byte >> shift) & 1) ? 0xFFu : 0x00u;
316 m0_mask[p] = ((W0 >> shift) & 1) ? 0xFFu : 0x00u;
317 }
318 u8 cols_a[16], cols_b[16], cols_c[16], cols_d[16];
319 spread_transpose16_symbol(lanes_a, cols_a);
320 spread_transpose16_symbol(lanes_b, cols_b);
321 spread_transpose16_symbol(lanes_c, cols_c);
322 spread_transpose16_symbol(lanes_d, cols_d);
323 for (int s = 0; s < 8; ++s) {
324 const u8 al = cols_a[2*s + 0], ah = cols_a[2*s + 1];
325 const u8 bl = cols_b[2*s + 0], bh = cols_b[2*s + 1];
326 const u8 cl = cols_c[2*s + 0], ch = cols_c[2*s + 1];
327 const u8 dl = cols_d[2*s + 0], dh = cols_d[2*s + 1];
328 for (int p = 0; p < 8; ++p) {
329 const u8 dm = d_mask[p], mm = m0_mask[p];
330 output_a[s*16 + p*2 + 0] = mm ^ (al & dm);
331 output_a[s*16 + p*2 + 1] = mm ^ (ah & dm);
332 output_b[s*16 + p*2 + 0] = mm ^ (bl & dm);
333 output_b[s*16 + p*2 + 1] = mm ^ (bh & dm);
334 output_c[s*16 + p*2 + 0] = mm ^ (cl & dm);
335 output_c[s*16 + p*2 + 1] = mm ^ (ch & dm);
336 output_d[s*16 + p*2 + 0] = mm ^ (dl & dm);
337 output_d[s*16 + p*2 + 1] = mm ^ (dh & dm);
338 }
339 }
340}
341
342} // namespace detail
343
345void wave8(u8 lane,
346 const Wave8BitExpansionLut& lut,
347 u8 (&FL_RESTRICT_PARAM output)[sizeof(Wave8Byte)]) FL_NO_EXCEPT {
348 Wave8Byte waveformSymbol;
349 detail::wave8_convert_byte_to_wave8byte(lane, lut, &waveformSymbol);
351 fl::bit_cast_ptr<const u32>(&waveformSymbol.symbols[0].data),
352 2);
353}
354
355} // namespace fl
356
Shared u32 "spread LUT" bit-matrix transpose primitive (no SIMD, no u64).
#define FL_OPTIMIZATION_LEVEL_O3_BEGIN
#define FL_OPTIMIZATION_LEVEL_O3_END
#define FL_OPTIMIZE_FUNCTION
#define FL_IRAM
#define FL_RESTRICT_PARAM
#define FL_WAVE8_SPREAD_TO_16(lane_u8_0, lane_u8_1, out_16)
Definition wave8.h:45
Out-of-line declarations for wave8 transposition internals.
ISR-safe memory operations (inline, header-only)
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16_bf1(const u8 lanes[16], u8 W0, u8 W1, u8 output[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16x2_pipe2(const Wave8Byte lane_waves_a[16], const Wave8Byte lane_waves_b[16], u8 output_a[16 *sizeof(Wave8Byte)], u8 output_b[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FASTLED_FORCE_INLINE FL_IRAM FL_OPTIMIZE_FUNCTION void spread_transpose16_symbol(const u8 l[16], u8 out[16])
Transpose one symbol of 16 lanes (16 input bytes) into 16 output bytes: 8 pulses × 2 bytes,...
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_4(const Wave8Byte lane_waves[4], u8 output[4 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:62
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16x4_pipe4(const Wave8Byte lane_waves_a[16], const Wave8Byte lane_waves_b[16], const Wave8Byte lane_waves_c[16], const Wave8Byte lane_waves_d[16], u8 output_a[16 *sizeof(Wave8Byte)], u8 output_b[16 *sizeof(Wave8Byte)], u8 output_c[16 *sizeof(Wave8Byte)], u8 output_d[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_8(const Wave8Byte lane_waves[8], u8 output[8 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16(const Wave8Byte lane_waves[16], u8 output[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_16x4_bf1_pipe4(const u8 lanes_a[16], const u8 lanes_b[16], const u8 lanes_c[16], const u8 lanes_d[16], u8 W0, u8 W1, u8 output_a[16 *sizeof(Wave8Byte)], u8 output_b[16 *sizeof(Wave8Byte)], u8 output_c[16 *sizeof(Wave8Byte)], u8 output_d[16 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FASTLED_FORCE_INLINE u32 spreadA(u8 v)
Pulses 7,6,5,4 of v (byte j = bit (7-j)). Depends only on the high nibble.
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_4_bf1(const u8 lanes[4], u8 W0, u8 W1, u8 output[4 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_8_bf1(const u8 lanes[8], u8 W0, u8 W1, u8 output[8 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FASTLED_FORCE_INLINE FL_IRAM FL_OPTIMIZE_FUNCTION void spread_transpose8_symbol(const u8 l[8], u8 out[8])
Transpose one symbol of 8 lanes (8 input bytes) into 8 output bytes: 8 pulses × 1 byte (bit L = lane ...
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_2(const Wave8Byte lane_waves[2], u8 output[2 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
Definition wave8.cpp.hpp:48
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_convert_byte_to_wave8byte(u8 byte_value, const Wave8BitExpansionLut &lut, Wave8Byte *output) FL_NO_EXCEPT
Definition wave8.cpp.hpp:24
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_transpose_2_bf1(const u8 lanes[2], u8 W0, u8 W1, u8 output[2 *sizeof(Wave8Byte)]) FL_NO_EXCEPT
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8_expand_byte(u8 byte_value, const Wave8ByteExpansionLut &lut, Wave8Byte *output) FL_NO_EXCEPT
Definition wave8.cpp.hpp:39
FASTLED_FORCE_INLINE u32 spreadB(u8 v)
Pulses 3,2,1,0 of v (byte j = bit (3-j)). Depends only on the low nibble.
Compile-time linker keep-alive hook for a single fl::Bus.
Definition bus_info.h:57
FL_OPTIMIZE_FUNCTION FL_IRAM FASTLED_FORCE_INLINE void memcpy_32(u32 *FL_RESTRICT_PARAM dst, const u32 *FL_RESTRICT_PARAM src, size_t count)
ISR-optimized 32-bit block copy for 4-byte aligned memory.
Definition memcpy.h:32
unsigned char u8
Definition stdint.h:131
FL_IRAM FL_OPTIMIZE_FUNCTION void wave8(u8 lane, const Wave8BitExpansionLut &lut, u8(&FL_RESTRICT_PARAM output)[sizeof(Wave8Byte)]) FL_NO_EXCEPT
Public single-lane wave8 encoder.
InputGamut g FL_NO_EXCEPT
Definition rgbw.h:121
To * bit_cast_ptr(void *storage) FL_NO_EXCEPT
Definition bit_cast.h:60
@ W1
White is second.
Definition eorder.h:26
@ W0
White is first.
Definition eorder.h:27
Base definition for an LED controller.
Definition crgb.hpp:179
Type-safe container for packed 8-bit wave pulse pattern.
Definition wave8.h:22