Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "defines.h"
11 :
12 :
13 : #include "functions.h"
14 : #include "rom_basop_util_lc3plus.h"
15 : #include <assert.h>
16 : #include <stdio.h>
17 : #include <stdlib.h>
18 : #include <string.h>
19 :
20 : /* channel coder specific constants and macros */
21 : #define RS16_CW_LEN_MAX 15
22 :
23 : #define FEC_N_MODES 4
24 : #define FEC_N_SYNDROMES_MAX 6
25 : #define FEC_N_ERR_POS_MAX 3
26 : #define FEC_N_ELP_COEFF_MAX 4
27 : #define FEC_N_ERR_SYMB_MAX 3
28 : #define FEC_N_MODE_DETECTION_CW 6
29 :
30 : #define SYNDROME_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_SYNDROMES_MAX)
31 : #define ELP_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_ELP_COEFF_MAX)
32 : #define ERR_POS_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_ERR_POS_MAX)
33 : #define ERR_SYMB_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_ERR_SYMB_MAX)
34 : #define DEG_ELP_IDX(mode_index, cw_index) ((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index))
35 :
36 : #define FEC_TOTAL_SYNDROME_SIZE (FEC_N_SYNDROMES_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
37 : #define FEC_TOTAL_ELP_SIZE (FEC_N_ELP_COEFF_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
38 : #define FEC_TOTAL_ERR_POS_SIZE (FEC_N_ERR_POS_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
39 : #define FEC_TOTAL_ERROR_SIZE (FEC_N_ERR_SYMB_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
40 : #define FEC_TOTAL_DEG_ELP_SIZE (FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
41 :
42 : #define ERROR_REPORT_BEC_MASK ((0x0FFF)>>1)
43 : #define ERROR_REPORT_EP1_OK ((0x1000)>>1)
44 : #define ERROR_REPORT_EP2_OK ((0x2000)>>1)
45 : #define ERROR_REPORT_EP3_OK ((0x4000)>>1)
46 : #define ERROR_REPORT_EP4_OK ((0x8000)>>1)
47 : #define ERROR_REPORT_ALL_OK (ERROR_REPORT_EP1_OK | ERROR_REPORT_EP2_OK | ERROR_REPORT_EP3_OK | ERROR_REPORT_EP4_OK)
48 :
49 : /* debugging switches */
50 :
51 : /* constants concerning mode detection */
52 : #define EP_RISK_THRESH_NS_M 21990
53 : #define EP_RISK_THRESH_NS_E -23
54 : #define EP_RISK_THRESH_OS_M 25166
55 : #define EP_RISK_THRESH_OS_E -10
56 :
57 : #define SIMPLE_FLOAT_1_MANTISSA 16384
58 :
59 : #define FEC_STATIC static
60 :
61 : /* DISCLAIMER: Strict instrumentation of GF16 arithmetic would have to take into account
62 : * the initial conversion of the arguments from UWord8 to Word16 (one move16() per argument).
63 : * Behind this is the assumption that one would store GF16 elements in Word16 for strict BASOP
64 : * implementation.
65 : */
66 :
67 : #define GF16_MUL(a, b) (UWord8)(move16(), gf16_mult_table[s_or((a), shl((b), 4))])
68 : #define GF16_MUL0(a, b) (UWord8)(move16(), gf16_mult_table[s_or((a), (b))])
69 : #define GF16_ADD(a, b) (UWord8) s_xor((a), (b))
70 :
71 : /* tables for finite field arithmetic */
72 : /* tables for arithmetic in GF(16) *
73 : * generator polynomial: 19
74 : * unit group generator (g): 2
75 : */
76 :
77 : static const UWord8 gf16_g_pow[16] = {1, 2, 4, 8, 3, 6, 12, 11, 5, 10, 7, 14, 15, 13, 9, 1};
78 : /* g_pow[i] contains g^i*/
79 :
80 : static const UWord8 gf16_log_g[16] = {255, 0, 1, 4, 2, 8, 5, 10, 3, 14, 9, 7, 6, 13, 11, 12};
81 : /* log_g[n] contains contains the value i such that g^i = n for n=1, 2, ..., 15, log_g[0] is set to 255 */
82 :
83 : static const UWord8 gf16_inv_table[16] = {255, 1, 9, 14, 13, 11, 7, 6, 15, 2, 12, 5, 10, 4, 3, 8};
84 : /* gf16_inv_table[n] contains the multiplicative inverse of n in GF(16) (1/0 is set to 255)*/
85 :
86 : /* RS16 generating polynomials (from lowest to highest coefficient without leading 1)*/
87 :
88 : static const UWord8 rs16_gp_d3[] = {8, 6};
89 : static const UWord8 rs16_gp_d5[] = {7, 8, 12, 13};
90 : static const UWord8 rs16_gp_d7[] = {12, 10, 12, 3, 9, 7};
91 :
92 : /* FEC mode signaling polynomials */
93 :
94 : #define EP_SIG_POLY_DEG 12
95 :
96 : static const UWord8 sig_polys[4][15] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
97 : {7, 15, 5, 6, 14, 9, 1, 3, 12, 10, 13, 3, 2, 0, 0},
98 : {7, 11, 14, 1, 2, 3, 12, 11, 6, 15, 7, 6, 12, 0, 0},
99 : {6, 15, 12, 2, 9, 15, 2, 8, 12, 3, 10, 5, 4, 0, 0}};
100 :
101 : static const UWord8 sig_poly_syndr[4][6] = {
102 : {0, 0, 0, 0, 0, 0}, {0, 4, 5, 11, 5, 8}, {0, 5, 9, 0, 1, 7}, {0, 12, 5, 12, 9, 8}};
103 :
104 : /* bit count table for error report (0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111) */
105 :
106 : static const UWord8 rs16_bit_count_table[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
107 :
108 : /* List of RS16 generators by Hamming distance */
109 :
110 : static const UWord8 *const rs16_gp_by_hd[8] = {NULL, NULL, NULL, rs16_gp_d3, NULL, rs16_gp_d5, NULL, rs16_gp_d7};
111 :
112 : /* fec config data */
113 :
114 : static const UWord8 hamming_distance_by_mode0[] = {1, 3, 3, 5, 7};
115 : static const UWord8 hamming_distance_by_mode1[] = {1, 1, 3, 5, 7};
116 :
117 : static const UWord8 crc1_bytes_by_mode0[] = {0, 3, 2, 2, 2};
118 : static const UWord8 crc1_bytes_by_mode1[] = {0, 3, 3, 3, 3};
119 : static const UWord8 crc2_bytes_by_mode[] = {0, 0, 2, 2, 2};
120 :
121 : /* fec mode risk table */
122 : typedef struct
123 : {
124 : UWord32 mantissa;
125 : Word16 exponent;
126 : } simple_float;
127 :
128 : static const simple_float risk_table_f[4][4] = {{{16384, 0}, {16384, 0}, {16384, 0}, {16384, 0}},
129 : {{16384, -8}, {26880, -1}, {16384, 0}, {16384, 0}},
130 : {{16384, -16}, {26880, -9}, {20475, -2}, {16384, 0}},
131 : {{16384, -24}, {26880, -17}, {20475, -10}, {19195, -4}}};
132 : /* bit error limits for slot size 40 */
133 : static Word16 const low_br_max_bit_errors_by_mode[] = {0, 0, 3, 9, 18};
134 :
135 : /*
136 : corresponding float values:
137 : {1.f, 1.f, 1.f, 1.f},
138 : {0.00390625f, 0.820312f, 1.f, 1.f},
139 : {1.52588e-05f, 0.00320435f, 0.312424f, 1.f},
140 : {5.96046e-08f, 1.2517e-05f, 0.00122041f, 0.0732243f}
141 : */
142 :
143 : /* internal encoder routines */
144 :
145 : FEC_STATIC void fec_interleave_pack(UWord8 *out, UWord8 *in, Word16 n_nibbles, Word16 n_codewords);
146 :
147 : FEC_STATIC void rs16_enc(UWord8 *iobuf, Word16 codeword_length, Word16 hamming_distance, Word16 fec_mode,
148 : Word16 signal_mode);
149 :
150 : /* internal decoder routines */
151 :
152 : FEC_STATIC void fec_deinterleave_unpack(UWord8 *out, UWord8 *in, Word16 n_nibbles, Word16 n_codewords);
153 :
154 : FEC_STATIC Word16 fec_data_preproc(Word16 mode, Word16 epmr, UWord8 *iobuf, UWord8 *cw_buf, Word16 data_bytes,
155 : Word16 slot_bytes, Word16 pc_split);
156 :
157 : FEC_STATIC void fec_data_postproc(Word16 mode, Word16 *epmr, UWord8 *iobuf, Word16 data_bytes, UWord8 *cw_buf,
158 : Word16 slot_bytes, Word16 pc_split, int *bfi);
159 :
160 : FEC_STATIC int rs16_detect_and_correct(UWord8 *iobuf, int n_symb, int n_codewords, Word16 *epmr, Word16 *error_report,
161 : int *bfi, UWord8 *array_of_trust, int ccc_flag_flag, Word16 *n_pccw, void *scratch);
162 :
163 : FEC_STATIC void rs16_calculate_six_syndromes(UWord8 *syndromes, UWord8 *cw, int cw_poly_deg);
164 :
165 : FEC_STATIC void rs16_calculate_four_syndromes(UWord8 *syndromes, UWord8 *cw, int cw_poly_deg);
166 :
167 : FEC_STATIC void rs16_calculate_two_syndromes(UWord8 *syndromes, UWord8 *cw, int cw_poly_deg);
168 :
169 : FEC_STATIC Word8 rs16_calculate_elp(UWord8 *elp, UWord8 *syndromes, Word16 hamming_distance);
170 :
171 : FEC_STATIC Word16 rs16_factorize_elp(UWord8 *error_locations, UWord8 *elp, Word16 deg_elp, Word16 max_pos);
172 :
173 : FEC_STATIC void rs16_calculate_errors(UWord8 *errors, UWord8 *err_pos, UWord8 *syndromes, Word8 deg_elp, Word8 t);
174 :
175 : /* auxiliary routines */
176 :
177 : FEC_STATIC Word16 crc1(UWord8 *data, Word16 data_size, Word16 epmr, UWord8 *hash, Word16 hash_size, Word16 check);
178 :
179 : FEC_STATIC Word16 fec_estimate_epmr_from_cw0(UWord8 *cw0, Word8 *t, UWord8 *syndromes, UWord8 *elp, Word8 *deg_elp,
180 : UWord8 *err_pos, UWord8 *err_symb, Word16 n_codewords, Word16 n_symb);
181 :
182 : FEC_STATIC void dw0_bitswap(UWord8 *dw0, Word16 mode, Word16 slot_bytes);
183 :
184 : FEC_STATIC Word16 cw0_get_epmr(UWord8 *cw0, Word16 epmr_position);
185 :
186 : FEC_STATIC Word16 dw0_get_epmr(UWord8 *dw0, Word16 mode, Word16 slot_size);
187 :
188 : FEC_STATIC Word16 crc2(UWord8 *data, Word16 data_size, UWord8 *hash, Word16 hash_size, Word16 check);
189 :
190 : FEC_STATIC simple_float simple_float_mul(simple_float op1, simple_float op2);
191 :
192 : FEC_STATIC Word16 simple_float_cmp(simple_float op1, simple_float op2);
193 :
194 : FEC_STATIC Word16 get_total_crc_size(Word16 slot_bytes, Word16 fec_mode, Word16 pc_split);
195 :
196 : FEC_STATIC Word16 get_n_codewords(Word16 slot_bytes);
197 :
198 : FEC_STATIC Word16 get_codeword_length(Word16 n_codewords, Word16 slot_nibbles, Word16 codeword_index);
199 :
200 :
201 :
202 0 : Word16 fec_get_n_pccw(Word16 slot_bytes, Word16 fec_mode, Word16 ccc_flag)
203 : {
204 : Dyn_Mem_Deluxe_In(
205 : Word16 n_pccw;
206 : );
207 :
208 0 : IF (sub(fec_mode, 3) == 0)
209 : {
210 0 : n_pccw = round_fx(L_sub(L_mult(2636, slot_bytes), 117377));
211 : }
212 0 : ELSE IF (sub(fec_mode, 4) == 0)
213 : {
214 0 : n_pccw = round_fx(L_sub(L_mult(2178, slot_bytes), 129115));
215 : }
216 : ELSE
217 : {
218 0 : n_pccw = 0; move16();
219 : }
220 :
221 0 : if (ccc_flag == 1 || sub(slot_bytes, 80) < 0)
222 : {
223 0 : n_pccw = 0; move16();
224 : }
225 :
226 : Dyn_Mem_Deluxe_Out();
227 0 : return n_pccw;
228 : }
229 :
230 0 : FEC_STATIC Word16 get_total_crc_size(Word16 slot_bytes, Word16 fec_mode, Word16 pc_split)
231 : {
232 : Dyn_Mem_Deluxe_In(
233 : Word16 n_crc;
234 : );
235 :
236 0 : n_crc = crc1_bytes_by_mode1[fec_mode]; move16();
237 0 : if (sub(slot_bytes, 40) == 0)
238 : {
239 0 : n_crc = crc1_bytes_by_mode0[fec_mode]; move16();
240 : }
241 :
242 0 : IF (pc_split > 0)
243 : {
244 0 : n_crc = add(n_crc, crc2_bytes_by_mode[fec_mode]);
245 : }
246 : Dyn_Mem_Deluxe_Out();
247 0 : return n_crc;
248 : }
249 :
250 0 : FEC_STATIC Word16 get_n_codewords(Word16 slot_bytes)
251 : {
252 : Dyn_Mem_Deluxe_In(
253 : Word16 i;
254 : );
255 :
256 0 : slot_bytes = shl(slot_bytes, 1);
257 :
258 0 : FOR (i = 0; slot_bytes > 0; i++)
259 : {
260 0 : slot_bytes = sub(slot_bytes, RS16_CW_LEN_MAX);
261 : }
262 :
263 : Dyn_Mem_Deluxe_Out();
264 0 : return i;
265 : }
266 :
267 0 : FEC_STATIC Word16 get_codeword_length(Word16 n_codewords, Word16 slot_nibbles, Word16 codeword_index)
268 : {
269 : Dyn_Mem_Deluxe_In(
270 : Word16 i;
271 : );
272 :
273 0 : slot_nibbles = sub(slot_nibbles, add(codeword_index, 1));
274 0 : slot_nibbles = sub(slot_nibbles, DEPR_i_mult(n_codewords, 13));
275 :
276 0 : FOR (i = 12; slot_nibbles >= 0; i++)
277 : {
278 0 : slot_nibbles = sub(slot_nibbles, n_codewords);
279 : }
280 :
281 : Dyn_Mem_Deluxe_Out();
282 0 : return add(i, 1);
283 : }
284 :
285 : /* Encoder */
286 :
287 0 : Word16 fec_get_data_size(Word16 fec_mode, Word16 ccc_flag, Word16 slot_bytes)
288 : /* not time critical */
289 : {
290 : Dyn_Mem_Deluxe_In(
291 : Word16 n_codewords, payload_size;
292 : );
293 :
294 0 : n_codewords = get_n_codewords(slot_bytes);
295 :
296 0 : assert(n_codewords == (2 * slot_bytes + RS16_CW_LEN_MAX - 1) / RS16_CW_LEN_MAX);
297 0 : payload_size = slot_bytes; move16();
298 :
299 0 : IF (fec_mode > 0)
300 : {
301 0 : IF (fec_mode == 1)
302 : {
303 0 : payload_size = sub(payload_size, 1);
304 : }
305 : ELSE
306 : {
307 0 : payload_size = sub(payload_size, DEPR_i_mult(sub(fec_mode, 1), n_codewords));
308 : }
309 0 : IF (slot_bytes == 40)
310 : {
311 0 : payload_size = sub(payload_size, crc1_bytes_by_mode0[fec_mode]); move16();
312 : }
313 : ELSE
314 : {
315 0 : payload_size = sub(payload_size, crc1_bytes_by_mode1[fec_mode]); move16();
316 : }
317 :
318 0 : IF (ccc_flag == 0 && fec_mode > 2 && slot_bytes >= 80)
319 : {
320 0 : payload_size = sub(payload_size, crc2_bytes_by_mode[fec_mode]);
321 : }
322 : }
323 :
324 : Dyn_Mem_Deluxe_Out();
325 0 : return payload_size;
326 : }
327 :
328 0 : Word16 fec_get_n_pc(Word16 fec_mode, Word16 n_pccw, Word16 slot_bytes)
329 : /* not time critical */
330 : {
331 : Dyn_Mem_Deluxe_In(
332 : Word16 n_codewords, pc_split, tmp;
333 : int i;
334 : );
335 :
336 0 : n_codewords = get_n_codewords(slot_bytes);
337 :
338 0 : assert(n_codewords == (2 * slot_bytes + RS16_CW_LEN_MAX - 1) / RS16_CW_LEN_MAX);
339 0 : pc_split = DEPR_i_mult(DEPR_i_mult(n_pccw, -2), sub(fec_mode, 1));
340 :
341 0 : IF (fec_mode == 1 || slot_bytes < 80)
342 : {
343 0 : pc_split = 0; move16();
344 : }
345 : ELSE
346 : {
347 0 : FOR (i = 0; i < n_pccw; i++)
348 : {
349 0 : tmp = get_codeword_length(n_codewords, add(slot_bytes, slot_bytes), sub(n_codewords, i + 1));
350 0 : assert(tmp == (2 * slot_bytes + i) / n_codewords);
351 0 : pc_split = add(pc_split, tmp);
352 : }
353 : }
354 :
355 : Dyn_Mem_Deluxe_Out();
356 0 : return pc_split;
357 : }
358 :
359 : /* functions for EPMR handling */
360 0 : FEC_STATIC void dw0_bitswap(UWord8 *dw0, Word16 mode, Word16 slot_bytes)
361 : /* swap epmr bits with bits that will be positioned at 30 and 32 in code word 0 */
362 : {
363 : Dyn_Mem_Deluxe_In(
364 : UWord8 tmp;
365 : int ind0, ind1, position;
366 : );
367 :
368 0 : position = sub(get_codeword_length(get_n_codewords(slot_bytes), shl(slot_bytes, 1), 0), 1);
369 :
370 0 : IF (sub(slot_bytes, 40) == 0)
371 : {
372 0 : ind0 = sub(shl(crc1_bytes_by_mode0[mode], 1), 1);
373 : }
374 : ELSE
375 : {
376 0 : ind0 = sub(shl(crc1_bytes_by_mode1[mode], 1), 1);
377 : }
378 :
379 0 : ind1 = sub(position, sub(hamming_distance_by_mode0[mode], 1));
380 :
381 : /* swap bits 2 and 3 of dw0[ind0] with bits 0 and 1 of dw0[ind1] */
382 0 : tmp = (UWord8) s_and(shr(dw0[ind0],2), 3);
383 0 : dw0[ind0] = (UWord8) s_and(dw0[ind0], 3);
384 0 : dw0[ind0] = (UWord8) s_or(dw0[ind0], shl(s_and(dw0[ind1], 3),2));
385 0 : dw0[ind1] = (UWord8) s_and(dw0[ind1], 12);
386 0 : dw0[ind1] = (UWord8) s_or(dw0[ind1], tmp);
387 :
388 : Dyn_Mem_Deluxe_Out();
389 0 : }
390 :
391 0 : FEC_STATIC Word16 cw0_get_epmr(UWord8 *cw0, Word16 position)
392 : {
393 : Dyn_Mem_Deluxe_In(
394 : Word16 epmr;
395 : );
396 0 : epmr = s_and(cw0[position], 3);
397 :
398 : Dyn_Mem_Deluxe_Out();
399 0 : return epmr;
400 : }
401 :
402 0 : FEC_STATIC Word16 dw0_get_epmr(UWord8 *dw0, Word16 mode, Word16 slot_size)
403 : {
404 : Dyn_Mem_Deluxe_In(
405 : int ncrc1;
406 : Word16 epmr;
407 : );
408 :
409 0 : ncrc1 = crc1_bytes_by_mode1[mode];
410 :
411 0 : if (sub(slot_size, 40) == 0)
412 : {
413 0 : ncrc1 = crc1_bytes_by_mode0[mode];
414 : }
415 :
416 0 : epmr = shr(dw0[2 * ncrc1 - 1], 2);
417 :
418 : Dyn_Mem_Deluxe_Out();
419 0 : return epmr;
420 : }
421 :
422 :
423 0 : FEC_STATIC Word16 fec_data_preproc(Word16 mode, Word16 epmr, UWord8 *iobuf, UWord8 *cw_buf, Word16 data_bytes,
424 : Word16 slot_bytes, Word16 pc_split)
425 : {
426 : Dyn_Mem_Deluxe_In(
427 : Word16 data_offset, n_crc1, n_crc2, tmp;
428 : int i, j;
429 : );
430 :
431 0 : tmp = sub(slot_bytes, data_bytes);
432 0 : data_offset = add(tmp, tmp);
433 :
434 : /* extract and reverse data*/
435 0 : j = sub(add(slot_bytes, slot_bytes), 1);
436 0 : FOR (i = 0; i < data_bytes; i++)
437 : {
438 0 : cw_buf[j--] = (UWord8)s_and(iobuf[i], 15); move16();
439 0 : cw_buf[j--] = (UWord8)shr(iobuf[i], 4); move16();
440 : }
441 :
442 : /* add crc hashes */
443 0 : IF (sub(slot_bytes, 40) == 0)
444 : {
445 0 : n_crc1 = crc1_bytes_by_mode0[mode]; move16();
446 : }
447 : ELSE
448 : {
449 0 : n_crc1 = crc1_bytes_by_mode1[mode]; move16();
450 : }
451 :
452 0 : IF (pc_split > 0 && sub(mode, 1) > 0)
453 : {
454 0 : n_crc2 = crc2_bytes_by_mode[mode]; move16();
455 : }
456 : ELSE
457 : {
458 0 : n_crc2 = 0; move16();
459 : }
460 :
461 0 : IF (n_crc2)
462 : {
463 0 : crc2(cw_buf + data_offset + 2 * data_bytes - pc_split, pc_split, cw_buf + data_offset - 2 * n_crc2, n_crc2, 0);
464 : }
465 0 : IF (n_crc1)
466 : {
467 0 : crc1(cw_buf + data_offset, 2 * data_bytes - pc_split, epmr, cw_buf + data_offset - 2 * (n_crc1 + n_crc2), n_crc1,
468 : 0);
469 : }
470 :
471 0 : tmp = add(n_crc1, n_crc2);
472 0 : data_offset = sub(data_offset, add(tmp, tmp));
473 :
474 0 : dw0_bitswap(cw_buf + data_offset, mode, slot_bytes);
475 :
476 : Dyn_Mem_Deluxe_Out();
477 0 : return data_offset;
478 : }
479 :
480 0 : void fec_encoder(Word16 mode, Word16 epmr, UWord8 *iobuf, Word16 data_bytes, Word16 slot_bytes, Word16 n_pccw,
481 : void *scratch)
482 : {
483 : Dyn_Mem_Deluxe_In(
484 : Word16 n_codewords, codeword_length, hd, redundancy_nibbles, cw_offset, dw_offset, pc_split;
485 : int i, j;
486 : UWord8 *cw_buf;
487 : );
488 :
489 0 : cw_offset = 0; move16();
490 0 : dw_offset = 0; move16();
491 0 : pc_split = 0; move16();
492 0 : cw_buf = scratch;
493 :
494 0 : n_codewords = get_n_codewords(slot_bytes);
495 0 : assert(n_codewords == (2 * slot_bytes + RS16_CW_LEN_MAX - 1) / RS16_CW_LEN_MAX);
496 :
497 : /* some sanity checks */
498 : {
499 0 : int tmp = slot_bytes;
500 0 : assert((slot_bytes >= FEC_SLOT_BYTES_MIN && slot_bytes <= FEC_SLOT_BYTES_MAX) &&
501 : "fec_encoder: slot_bytes out of range");
502 0 : tmp -= mode == 1 ? 1 : n_codewords * (mode - 1); // reed solomon redundancy
503 0 : tmp -= slot_bytes == 40 ? crc1_bytes_by_mode0[mode] : crc1_bytes_by_mode1[mode]; // crc1
504 0 : tmp -= (n_pccw > 0) && (mode > 1) ? crc2_bytes_by_mode[mode] : 0; // crc2
505 0 : assert(data_bytes == tmp && "fec_encoder: inconsistent payload size");
506 0 : assert(n_codewords - n_pccw >= 6);
507 : }
508 :
509 : /* data preproc: re-ordering and hash extension */
510 0 : pc_split = fec_get_n_pc(mode, n_pccw, slot_bytes);
511 :
512 0 : dw_offset = fec_data_preproc(mode, epmr, iobuf, cw_buf, data_bytes, slot_bytes, pc_split);
513 :
514 : /* encoding of first data word*/
515 0 : hd = hamming_distance_by_mode0[mode]; move16();
516 0 : redundancy_nibbles = sub(hd, 1);
517 0 : codeword_length = get_codeword_length(n_codewords, add(slot_bytes, slot_bytes), 0);
518 :
519 0 : assert(codeword_length == (2 * slot_bytes - 1) / n_codewords + 1);
520 :
521 0 : FOR (j = redundancy_nibbles; j < codeword_length; (j++, dw_offset++))
522 : {
523 0 : cw_buf[j] = cw_buf[dw_offset]; move16();
524 : }
525 :
526 0 : rs16_enc(cw_buf, codeword_length, hd, mode, 1);
527 :
528 0 : cw_offset = add(cw_offset, codeword_length);
529 :
530 : /* encoding of remaining data words */
531 0 : hd = hamming_distance_by_mode1[mode]; move16();
532 0 : redundancy_nibbles = sub(hd, 1);
533 :
534 0 : FOR (i = 1; i < n_codewords; i++)
535 : {
536 0 : codeword_length = get_codeword_length(n_codewords, add(slot_bytes, slot_bytes), i);
537 :
538 0 : assert(codeword_length == (2 * slot_bytes - i - 1) / n_codewords + 1);
539 0 : FOR (j = redundancy_nibbles; j < codeword_length; (j++, dw_offset++))
540 : {
541 0 : cw_buf[cw_offset + j] = cw_buf[dw_offset]; move16();
542 : }
543 :
544 0 : rs16_enc(cw_buf + cw_offset, codeword_length, hd, mode, sub(i, 6) < 0);
545 :
546 0 : cw_offset = add(cw_offset, codeword_length);
547 : }
548 :
549 0 : assert(cw_offset == 2 * slot_bytes && dw_offset == 2 * slot_bytes);
550 :
551 0 : fec_interleave_pack(iobuf, cw_buf, add(slot_bytes, slot_bytes), n_codewords);
552 :
553 :
554 : Dyn_Mem_Deluxe_Out();
555 0 : }
556 :
557 0 : FEC_STATIC void rs16_enc(UWord8 *iobuf, Word16 codeword_length, Word16 hamming_distance, Word16 fec_mode,
558 : Word16 signal_mode)
559 : /* expects (data polynomial) * x^(hamming_distance - 1) in iobuf */
560 : {
561 :
562 : Dyn_Mem_Deluxe_In(
563 : UWord8 const *gp;
564 : UWord8 shift_buffer[RS16_CW_LEN_MAX + 1], lc;
565 : int i, j, deg_gp;
566 : );
567 :
568 0 : basop_memset(shift_buffer, 0, sizeof(shift_buffer));
569 0 : gp = rs16_gp_by_hd[hamming_distance]; move16();
570 0 : deg_gp = sub(hamming_distance, 1);
571 :
572 0 : IF (sub(hamming_distance, 1) > 0)
573 : {
574 0 : assert(codeword_length > deg_gp);
575 :
576 : /* initialize redundancy part to zero */
577 0 : basop_memset(iobuf, 0, deg_gp);
578 :
579 : /* initialize shift_buffer */
580 0 : basop_memmove(shift_buffer + 1, iobuf + codeword_length - deg_gp, deg_gp);
581 :
582 : /* calculate remainder */
583 0 : FOR (i = codeword_length - deg_gp - 1; i >= 0; i--)
584 : {
585 0 : shift_buffer[0] = iobuf[i]; move16();
586 0 : lc = (UWord8)shl(shift_buffer[deg_gp], 4); move16();
587 0 : FOR (j = deg_gp - 1; j >= 0; j--)
588 : {
589 0 : shift_buffer[j + 1] = GF16_ADD(shift_buffer[j], GF16_MUL0(gp[j], lc)); move16();
590 : }
591 : }
592 :
593 : /* add remainder to shifted data polynomial */
594 0 : FOR (i = 0; i < deg_gp; i++)
595 : {
596 0 : iobuf[i] = shift_buffer[i + 1]; move16();
597 : }
598 :
599 : /* add signaling polynomial */
600 0 : IF (signal_mode)
601 : {
602 0 : assert(codeword_length > EP_SIG_POLY_DEG);
603 0 : FOR (i = 0; i <= EP_SIG_POLY_DEG; i++)
604 : {
605 0 : iobuf[i] = GF16_ADD(iobuf[i], sig_polys[fec_mode - 1][i]); move16();
606 : }
607 : }
608 : }
609 :
610 : Dyn_Mem_Deluxe_Out();
611 0 : }
612 :
613 0 : FEC_STATIC void fec_interleave_pack(UWord8 *out, UWord8 *in, Word16 n_nibbles, Word16 n_codewords)
614 : {
615 : Dyn_Mem_Deluxe_In(
616 : Word16 out_offset, cw_offset, codeword_length;
617 : int i, j;
618 : );
619 :
620 0 : out_offset = 0; move16();
621 0 : cw_offset = 0; move16();
622 :
623 : /* initialize output buffer to zero */
624 0 : basop_memset(out, 0, shr(n_nibbles, 1));
625 :
626 : /* interleave and pack codewords */
627 0 : FOR (i = 0; i < n_codewords; i++)
628 : {
629 0 : codeword_length = get_codeword_length(n_codewords, n_nibbles, i);
630 :
631 0 : assert(codeword_length == (n_nibbles - i - 1) / n_codewords + 1);
632 0 : FOR (j = 0; j < codeword_length; j++)
633 : {
634 0 : out_offset = add(DEPR_i_mult(j, n_codewords), i);
635 0 : out_offset = sub(n_nibbles, add(out_offset, 1));
636 0 : out[out_offset >> 1] =
637 0 : (UWord8)s_or(out[out_offset >> 1], shl(in[cw_offset], shl(s_and(out_offset, 1), 2))); move16();
638 0 : cw_offset = add(cw_offset, 1);
639 : }
640 : }
641 :
642 0 : assert(cw_offset == n_nibbles);
643 : Dyn_Mem_Deluxe_Out();
644 0 : }
645 :
646 : /* Decoder */
647 0 : FEC_STATIC void fec_data_postproc(Word16 mode, Word16 *epmr, UWord8 *obuf, Word16 data_bytes, UWord8 *cw_buf,
648 : Word16 slot_bytes, Word16 pc_split, int *bfi)
649 : {
650 : Dyn_Mem_Deluxe_In(
651 : Word16 i;
652 : Word16 n_crc1, n_crc2;
653 : Word16 cw_buf_len;
654 : Word16 tmp_epmr;
655 : );
656 :
657 0 : n_crc1 = crc1_bytes_by_mode1[mode]; move16();
658 0 : if (sub(slot_bytes, 40) == 0)
659 : {
660 0 : n_crc1 = crc1_bytes_by_mode0[mode]; move16();
661 : }
662 :
663 0 : n_crc2 = 0; move16();
664 0 : if (pc_split > 0)
665 : {
666 0 : n_crc2 = crc2_bytes_by_mode[mode]; move16();
667 : }
668 :
669 0 : assert(n_crc1 == (slot_bytes == 40 ? crc1_bytes_by_mode0[mode] : crc1_bytes_by_mode1[mode]));
670 0 : assert(n_crc2 == ((pc_split > 0) && (mode > 1) ? crc2_bytes_by_mode[mode] : 0));
671 :
672 0 : cw_buf_len = 2 * (data_bytes + n_crc1 + n_crc2);
673 :
674 0 : IF (sub(mode, 1))
675 : {
676 : /* reverse bit-swap */
677 0 : dw0_bitswap(cw_buf, mode, slot_bytes);
678 0 : tmp_epmr = dw0_get_epmr(cw_buf, mode, slot_bytes);
679 :
680 0 : IF (crc1(cw_buf + shl(add(n_crc1, n_crc2), 1), sub(shl(data_bytes, 1), pc_split), tmp_epmr, cw_buf, n_crc1, 1))
681 : {
682 0 : *bfi = 1; move32();
683 :
684 : Dyn_Mem_Deluxe_Out();
685 0 : return;
686 : }
687 : else
688 : {
689 0 : *epmr = tmp_epmr;
690 : }
691 : }
692 :
693 0 : test();
694 0 : IF (pc_split > 0 && sub(*bfi, 2) != 0)
695 : {
696 0 : IF (crc2(cw_buf + sub(shl(add(data_bytes, add(n_crc1, n_crc2)), 1), pc_split), pc_split,
697 : cw_buf + shl(n_crc1, 1), n_crc2, 1))
698 : {
699 0 : *bfi = 2; move32();
700 : }
701 : }
702 :
703 0 : FOR (i = 0; i < data_bytes; i++)
704 : {
705 0 : obuf[i] = (UWord8)s_or(cw_buf[cw_buf_len - 2 * i - 1], shl(cw_buf[cw_buf_len - 2 * i - 2], 4)); move16();
706 : }
707 : Dyn_Mem_Deluxe_Out();
708 : }
709 :
710 0 : int fec_decoder(UWord8 *iobuf, Word16 slot_bytes, int *data_bytes, Word16 *epmr, Word16 ccc_flag, Word16 *n_pccw,
711 : int *bfi, Word16 *be_bp_left, Word16 *be_bp_right, Word16 *n_pc, Word16 *m_fec, void *scratch)
712 : {
713 : Dyn_Mem_Deluxe_In(
714 : UWord8 *my_scratch;
715 : UWord8 *cw_buf;
716 : UWord8 *array_of_trust;
717 : Word16 i, j;
718 : Word16 cw_offset, dw_offset;
719 : Word16 n_codewords, redundancy_nibbles, codeword_length;
720 : Word16 mode, error_report;
721 : Word16 n_crc;
722 : Word16 first_bad_cw;
723 : Word16 pc_split;
724 : );
725 :
726 0 : IF (*bfi == 1)
727 : {
728 : Dyn_Mem_Deluxe_Out();
729 0 : return ERROR_REPORT_BEC_MASK;
730 : }
731 :
732 0 : if (slot_bytes < FEC_SLOT_BYTES_MIN || slot_bytes > FEC_SLOT_BYTES_MAX)
733 : {
734 0 : *bfi = 1;
735 0 : return ERROR_REPORT_BEC_MASK;
736 : }
737 :
738 0 : my_scratch = (UWord8 *)scratch; move32();
739 0 : cw_buf = my_scratch; move32();
740 0 : my_scratch += 2 * slot_bytes;
741 :
742 0 : IF (ccc_flag == 0)
743 : {
744 0 : *be_bp_left = -1; move16();
745 0 : *be_bp_right = -1; move16();
746 : }
747 :
748 0 : n_codewords = get_n_codewords(slot_bytes);
749 :
750 0 : array_of_trust = my_scratch; move32();
751 0 : my_scratch += n_codewords;
752 :
753 : /* extract and de-interleave nibbles */
754 0 : fec_deinterleave_unpack(cw_buf, iobuf, 2 * slot_bytes, n_codewords);
755 :
756 : /* mode detection and error correction */
757 0 : mode = rs16_detect_and_correct(cw_buf, 2 * slot_bytes, n_codewords, epmr, &error_report, bfi, array_of_trust,
758 : ccc_flag, n_pccw, (void *)my_scratch);
759 :
760 : /* for normal slots the maximal number of bit errors is limited */
761 0 : test();
762 : #ifndef APPLY_MAX_ERRORS
763 0 : IF (sub(slot_bytes, 40) == 0 && mode > 0)
764 : {
765 0 : IF (sub(error_report & ERROR_REPORT_BEC_MASK, low_br_max_bit_errors_by_mode[mode]) > 0)
766 : {
767 0 : error_report &= ERROR_REPORT_BEC_MASK;
768 0 : mode = -1; move16();
769 0 : *bfi = 1; move32();
770 : }
771 : ELSE
772 : {
773 0 : IF (sub(error_report & ERROR_REPORT_BEC_MASK, low_br_max_bit_errors_by_mode[2]) > 0)
774 : {
775 0 : error_report &= ~ERROR_REPORT_EP2_OK;
776 : }
777 0 : IF (sub(error_report & ERROR_REPORT_BEC_MASK, low_br_max_bit_errors_by_mode[3])>0)
778 : {
779 0 : error_report &= ~ERROR_REPORT_EP3_OK;
780 : }
781 : }
782 : }
783 : #endif
784 :
785 0 : IF (sub(*bfi, 1) == 0)
786 : {
787 0 : *data_bytes = 0; move16();
788 :
789 : Dyn_Mem_Deluxe_Out();
790 0 : return error_report;
791 : }
792 :
793 : /* initialization for decoding */
794 0 : *data_bytes = fec_get_data_size(mode, ccc_flag, slot_bytes); move32();
795 0 : pc_split = fec_get_n_pc(mode, *n_pccw, slot_bytes);
796 0 : n_crc = get_total_crc_size(slot_bytes, mode, pc_split);
797 :
798 : /* decoding of first code word */
799 0 : redundancy_nibbles = sub(hamming_distance_by_mode0[mode], 1);
800 0 : codeword_length = get_codeword_length(n_codewords, add(slot_bytes, slot_bytes), 0);
801 :
802 0 : dw_offset = 0; move16();
803 0 : cw_offset = 0; move16();
804 :
805 0 : FOR (j = redundancy_nibbles; j < codeword_length; j++)
806 : {
807 0 : cw_buf[dw_offset++] = cw_buf[j]; move16();
808 : }
809 0 : cw_offset = add(cw_offset, codeword_length);
810 :
811 : /* decoding of remaining code words */
812 0 : redundancy_nibbles = sub(hamming_distance_by_mode1[mode], 1);
813 :
814 0 : FOR (i = 1; i < n_codewords; i++)
815 : {
816 0 : codeword_length = get_codeword_length(n_codewords, add(slot_bytes, slot_bytes), i);
817 :
818 0 : FOR (j = redundancy_nibbles; j < codeword_length; j++)
819 : {
820 0 : cw_buf[dw_offset++] = cw_buf[j + cw_offset]; move16();
821 : }
822 :
823 0 : cw_offset = add(cw_offset, codeword_length);
824 : }
825 :
826 0 : assert(2 * (*data_bytes + n_crc) == dw_offset && 2 * slot_bytes == cw_offset);
827 :
828 : /* data postproc: hash validation and re-ordering */
829 :
830 0 : fec_data_postproc(mode, epmr, iobuf, *data_bytes, cw_buf, slot_bytes, pc_split, bfi);
831 :
832 0 : IF (sub(*bfi, 1) == 0)
833 : {
834 0 : *data_bytes = 0; move32();
835 0 : error_report &= ERROR_REPORT_BEC_MASK;
836 : Dyn_Mem_Deluxe_Out();
837 0 : return error_report;
838 : }
839 :
840 0 : IF (*bfi == 2)
841 : {
842 0 : first_bad_cw = 0; move16();
843 0 : array_of_trust[*n_pccw] = 0; move16();
844 0 : WHILE (array_of_trust[first_bad_cw] != 0)
845 : {
846 0 : first_bad_cw = add(first_bad_cw, 1);
847 : }
848 0 : IF (sub(first_bad_cw, *n_pccw) == 0)
849 : {
850 : /* this is the case when CRC failed */
851 0 : *be_bp_left = 0; move16();
852 : }
853 : ELSE
854 : {
855 0 : *be_bp_left = extract_l(L_mult0(fec_get_n_pc(mode, first_bad_cw, slot_bytes), 4)); move16();
856 : }
857 :
858 0 : FOR (i = *n_pccw - 1; i >= 0; i--)
859 : {
860 0 : if (!array_of_trust[i])
861 : {
862 0 : BREAK;
863 : }
864 : }
865 0 : IF (i < 0)
866 : {
867 0 : i = sub(*n_pccw, 1);
868 : }
869 0 : *be_bp_right = sub(extract_l(L_mult0(fec_get_n_pc(mode, i+1, slot_bytes), 4)), 1); move16();
870 :
871 : }
872 :
873 0 : IF (ccc_flag == 0)
874 : {
875 0 : *n_pc = pc_split; move16();
876 0 : *m_fec = mode; move16();
877 : }
878 :
879 :
880 : Dyn_Mem_Deluxe_Out();
881 0 : return error_report;
882 : }
883 :
884 0 : FEC_STATIC void fec_deinterleave_unpack(UWord8 *out, UWord8 *in, Word16 n_nibbles, Word16 n_codewords)
885 : {
886 : Dyn_Mem_Deluxe_In(
887 : Word16 in_offset, out_offset, codeword_length;
888 : int i, j;
889 : );
890 :
891 0 : in_offset = 0; move16();
892 0 : out_offset = 0; move16();
893 :
894 : /* unpack nibbles in input buffer and deinterleave codewords */
895 0 : FOR (i = 0; i < n_codewords; i++)
896 : {
897 0 : codeword_length = get_codeword_length(n_codewords, n_nibbles, i);
898 0 : FOR (j = 0; j < codeword_length; (j++, out_offset++))
899 : {
900 0 : in_offset = add(DEPR_i_mult(j, n_codewords), i);
901 0 : in_offset = sub(n_nibbles, add(in_offset, 1));
902 0 : out[out_offset] = (UWord8)s_and(shr(in[in_offset >> 1], shl(s_and(in_offset, 1), 2)), 15); move16();
903 : }
904 : }
905 :
906 0 : assert(out_offset == n_nibbles);
907 : Dyn_Mem_Deluxe_Out();
908 0 : }
909 :
910 0 : FEC_STATIC Word16 fec_estimate_epmr_from_cw0(UWord8 *cw0, Word8 *t, UWord8 *syndromes, UWord8 *elp, Word8 *deg_elp,
911 : UWord8 *err_pos, UWord8 *err_symb, Word16 n_codewords, Word16 n_symb)
912 : {
913 : Dyn_Mem_Deluxe_In(
914 : int epmr_lowest_risk_exp;
915 : int start, inc, i, n_candidates;
916 : int first_codeword_length;
917 : int mode_counter;
918 : Word16 epmr;
919 : );
920 :
921 0 : epmr_lowest_risk_exp = 0;
922 0 : first_codeword_length = get_codeword_length(n_codewords, n_symb, 0);
923 0 : start = 2;
924 0 : inc = 1;
925 0 : n_candidates = 0;
926 :
927 : /* test if first code word decodes in mode 0 or 1 without error correction */
928 0 : test();
929 0 : IF (s_or(syndromes[SYNDROME_IDX(0, 0)], syndromes[SYNDROME_IDX(0, 0) + 1]) == 0 ||
930 : s_or(syndromes[SYNDROME_IDX(1, 0)], syndromes[SYNDROME_IDX(1, 0) + 1]) == 0)
931 : {
932 0 : epmr_lowest_risk_exp = risk_table_f[1][0].exponent; move16();
933 : }
934 : /* test if first code word decodes in mode 2 or 3 with lower risk */
935 0 : IF (sub(deg_elp[DEG_ELP_IDX(2, 0)], t[2]) <= 0)
936 : {
937 0 : IF (add(risk_table_f[2][deg_elp[DEG_ELP_IDX(2, 0)]].exponent, 8) <= 0)
938 : {
939 0 : n_candidates++;
940 0 : start = 2;
941 : }
942 : }
943 :
944 0 : IF (sub(deg_elp[DEG_ELP_IDX(3, 0)], t[3]) <= 0)
945 : {
946 0 : IF (add(risk_table_f[3][deg_elp[DEG_ELP_IDX(3, 0)]].exponent, 8) <= 0)
947 : {
948 0 : n_candidates++;
949 0 : start = 3;
950 : }
951 : }
952 :
953 0 : IF (sub(n_candidates, 1) > 0)
954 : {
955 : /* decide on order if mode 2 and 3 are considered */
956 0 : IF (simple_float_cmp(risk_table_f[2][deg_elp[DEG_ELP_IDX(2, 0)]], risk_table_f[3][deg_elp[DEG_ELP_IDX(3, 0)]]) <
957 : 0)
958 : {
959 0 : start = 2;
960 0 : inc = 1;
961 : }
962 : ELSE
963 : {
964 0 : start = 3;
965 0 : inc = -1;
966 : }
967 : }
968 :
969 0 : FOR ((mode_counter = start, i = 0); i < n_candidates; (mode_counter += inc, i++))
970 : {
971 0 : IF (sub(risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, 0)]].exponent, epmr_lowest_risk_exp) < 0)
972 : {
973 0 : IF (!rs16_factorize_elp(err_pos + ERR_POS_IDX(mode_counter, 0), elp + ELP_IDX(mode_counter, 0),
974 : deg_elp[DEG_ELP_IDX(mode_counter, 0)], sub(first_codeword_length, 1)))
975 : {
976 : /* code word is decodable with error correction */
977 0 : epmr_lowest_risk_exp = risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, 0)]].exponent;
978 :
979 0 : rs16_calculate_errors(err_symb + ERR_SYMB_IDX(mode_counter, 0), err_pos + ERR_POS_IDX(mode_counter, 0),
980 0 : syndromes + SYNDROME_IDX(mode_counter, 0), deg_elp[DEG_ELP_IDX(mode_counter, 0)],
981 0 : t[mode_counter]);
982 :
983 0 : FOR (i = 0; i < deg_elp[DEG_ELP_IDX(mode_counter, 0)]; i++)
984 : {
985 0 : cw0[err_pos[ERR_POS_IDX(mode_counter, 0) + i]] = GF16_ADD(
986 : cw0[err_pos[ERR_POS_IDX(mode_counter, 0) + i]], err_symb[ERR_SYMB_IDX(mode_counter, 0) + i]);
987 : }
988 0 : BREAK;
989 : }
990 : }
991 : }
992 :
993 0 : epmr = cw0_get_epmr(cw0, sub(first_codeword_length, 1));
994 :
995 0 : IF (add(epmr_lowest_risk_exp, 16) > 0)
996 : {
997 0 : epmr = add(epmr, 4); move16();
998 : }
999 0 : IF (add(epmr_lowest_risk_exp, 8) > 0)
1000 : {
1001 0 : epmr = add(epmr, 4); move16();
1002 : }
1003 :
1004 : Dyn_Mem_Deluxe_Out();
1005 0 : return epmr;
1006 : }
1007 :
1008 0 : FEC_STATIC int rs16_detect_and_correct(UWord8 *iobuf, int n_symb, int n_codewords, Word16 *epmr, Word16 *error_report,
1009 : int *bfi, UWord8 *array_of_trust, int ccc_flag, Word16 *n_pccw, void *scratch)
1010 : {
1011 : Dyn_Mem_Deluxe_In(
1012 : UWord8 * syndromes;
1013 : UWord8 * elp;
1014 : UWord8 * err_pos;
1015 : UWord8 * err_symb;
1016 : Word8 t[FEC_N_MODES];
1017 : Word8 * deg_elp;
1018 : UWord8 * my_scratch;
1019 : UWord8 blacklist[FEC_N_MODES];
1020 : UWord8 const *hamming_distance;
1021 :
1022 : Word16 i, cw_counter, mode_counter, cw_offset;
1023 : Word16 codeword_length;
1024 : Word16 mode;
1025 : Word16 mode_candidates[4];
1026 : Word16 mode_broken[4];
1027 : Word16 error_report_ep_ok[4];
1028 : Word16 n_mode_candidates;
1029 : Word16 broken_cw, n_broken_cw;
1030 : Word16 j, idx_min;
1031 : Word16 n_pccw0;
1032 : simple_float val_min_f;
1033 : Word16 tmp;
1034 : Word16 epmr_position;
1035 : simple_float dec_risk_f[FEC_N_MODES];
1036 : simple_float risk_min_f;
1037 : simple_float ep_risk_thresh;
1038 :
1039 : int epmr_dec_fail_increment;
1040 :
1041 : void (*syndr_calc[3])(UWord8 *, UWord8 *, int);
1042 : );
1043 :
1044 : /* initialization */
1045 0 : blacklist[0] = 0; move16();
1046 0 : blacklist[1] = 0; move16();
1047 0 : blacklist[2] = 0; move16();
1048 0 : blacklist[3] = 0; move16();
1049 0 : mode_broken[0] = 0; move16();
1050 0 : mode_broken[1] = 0; move16();
1051 0 : mode_broken[2] = 0; move16();
1052 0 : mode_broken[3] = 0; move16();
1053 0 : error_report_ep_ok[0] = ERROR_REPORT_EP1_OK;
1054 0 : error_report_ep_ok[1] = ERROR_REPORT_EP2_OK;
1055 0 : error_report_ep_ok[2] = ERROR_REPORT_EP3_OK;
1056 0 : error_report_ep_ok[3] = ERROR_REPORT_EP4_OK;
1057 0 : my_scratch = (UWord8 *)scratch;
1058 0 : hamming_distance = &hamming_distance_by_mode0[1];
1059 0 : mode = -1; move16();
1060 0 : n_mode_candidates = 0; move16();
1061 0 : risk_min_f.mantissa = SIMPLE_FLOAT_1_MANTISSA; move16();
1062 0 : risk_min_f.exponent = 0; move16();
1063 :
1064 0 : IF (n_symb <= 80)
1065 : {
1066 0 : ep_risk_thresh.mantissa = EP_RISK_THRESH_NS_M; move16();
1067 0 : ep_risk_thresh.exponent = EP_RISK_THRESH_NS_E; move16();
1068 : }
1069 : ELSE
1070 : {
1071 0 : ep_risk_thresh.mantissa = EP_RISK_THRESH_OS_M; move16();
1072 0 : ep_risk_thresh.exponent = EP_RISK_THRESH_OS_E; move16();
1073 : }
1074 :
1075 0 : syndr_calc[0] = &rs16_calculate_two_syndromes;
1076 0 : syndr_calc[1] = &rs16_calculate_four_syndromes;
1077 0 : syndr_calc[2] = &rs16_calculate_six_syndromes;
1078 :
1079 0 : FOR (i = 0; i < FEC_N_MODES; i++)
1080 : {
1081 0 : t[i] = (Word8)shr(sub(hamming_distance[i], 1), 1); move16();
1082 : }
1083 :
1084 0 : syndromes = my_scratch;
1085 0 : my_scratch += FEC_TOTAL_SYNDROME_SIZE;
1086 0 : elp = my_scratch;
1087 0 : my_scratch += FEC_TOTAL_ELP_SIZE;
1088 0 : err_pos = my_scratch;
1089 0 : my_scratch += FEC_TOTAL_ERR_POS_SIZE;
1090 0 : err_symb = my_scratch;
1091 0 : my_scratch += FEC_TOTAL_ERROR_SIZE;
1092 0 : deg_elp = (Word8 *)my_scratch;
1093 0 : my_scratch += FEC_TOTAL_DEG_ELP_SIZE;
1094 :
1095 0 : *error_report = 0; move16();
1096 0 : *bfi = 0; move32();
1097 :
1098 : /* mode detection (stage 1) */
1099 0 : codeword_length = get_codeword_length(n_codewords, n_symb, 0);
1100 :
1101 0 : epmr_position = sub(codeword_length, 1);
1102 :
1103 0 : rs16_calculate_two_syndromes(syndromes + SYNDROME_IDX(0, 0), iobuf, sub(codeword_length, 1));
1104 :
1105 0 : IF (s_or(syndromes[0 + SYNDROME_IDX(0, 0)], syndromes[1 + SYNDROME_IDX(0, 0)]) == 0)
1106 : {
1107 :
1108 : /* data validation for fec mode 1 */
1109 0 : *epmr = cw0_get_epmr(iobuf, epmr_position);
1110 :
1111 0 : dw0_bitswap(iobuf + 2, 1, n_symb / 2);
1112 :
1113 0 : IF (!crc1(iobuf + 8, sub(n_symb, 8), *epmr, iobuf + 2, 3, 1))
1114 : {
1115 0 : mode = 0; move16();
1116 0 : *error_report |= ERROR_REPORT_ALL_OK;
1117 : Dyn_Mem_Deluxe_Out();
1118 0 : return add(mode, 1);
1119 : }
1120 : ELSE
1121 : {
1122 : /* reverse bit swap */
1123 0 : dw0_bitswap(iobuf + 2, 1, n_symb / 2);
1124 :
1125 0 : *epmr = add(*epmr, 4); move16();
1126 : }
1127 : }
1128 :
1129 0 : blacklist[0] = 1; move16();
1130 :
1131 : /* mode detection (stage 2) */
1132 :
1133 : /* calculate syndromes of code words 0 to 5 and modes 1 to 3 */
1134 0 : cw_offset = 0; move16();
1135 :
1136 0 : FOR (cw_counter = 0; cw_counter < 6; cw_counter++)
1137 : {
1138 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1139 :
1140 0 : rs16_calculate_six_syndromes(syndromes + SYNDROME_IDX(1, cw_counter), iobuf + cw_offset,
1141 0 : sub(codeword_length, 1));
1142 :
1143 0 : cw_offset = add(cw_offset, codeword_length);
1144 :
1145 0 : FOR (mode_counter = FEC_N_MODES - 1; mode_counter >= 1; mode_counter--)
1146 : {
1147 0 : FOR (i = 0; i < sub(hamming_distance[mode_counter], 1); i++)
1148 : {
1149 0 : syndromes[SYNDROME_IDX(mode_counter, cw_counter) + i] = GF16_ADD(
1150 0 : syndromes[SYNDROME_IDX(1, cw_counter) + i], sig_poly_syndr[mode_counter][i]); move16();
1151 : }
1152 : }
1153 : }
1154 :
1155 : /* check for valid code words */
1156 0 : FOR (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1157 : {
1158 0 : n_broken_cw = 0;
1159 0 : FOR (cw_counter = 0; cw_counter < 6; cw_counter++)
1160 : {
1161 0 : broken_cw = 0;
1162 0 : FOR (i = 0; i < sub(hamming_distance[mode_counter], 1); i++)
1163 : {
1164 0 : broken_cw = s_or(broken_cw, syndromes[SYNDROME_IDX(mode_counter, cw_counter) + i]); move16();
1165 : }
1166 0 : IF (broken_cw != 0)
1167 : {
1168 0 : n_broken_cw = add(n_broken_cw, 1);
1169 : }
1170 : }
1171 :
1172 0 : IF (n_broken_cw == 0)
1173 : {
1174 0 : mode = mode_counter; move16();
1175 0 : cw_offset = 0; move16();
1176 :
1177 0 : *epmr = cw0_get_epmr(iobuf, epmr_position);
1178 :
1179 0 : FOR (cw_counter = 0; cw_counter < 6; cw_counter++)
1180 : {
1181 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1182 0 : FOR (i = 0; i <= EP_SIG_POLY_DEG; i++)
1183 : {
1184 0 : iobuf[cw_offset + i] = GF16_ADD(iobuf[cw_offset + i], sig_polys[mode][i]);
1185 : }
1186 0 : cw_offset = add(cw_offset, codeword_length);
1187 : }
1188 : }
1189 : }
1190 :
1191 0 : IF (mode < 0) /* mode hasn't been detected so far -> errors occurred in transmission */
1192 : {
1193 : /* calculate error locator polynomials for code words 0 to 5 */
1194 0 : FOR (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1195 : {
1196 0 : FOR (cw_counter = 0; cw_counter < 6; cw_counter++)
1197 : {
1198 0 : deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)] = rs16_calculate_elp(
1199 0 : elp + ELP_IDX(mode_counter, cw_counter), syndromes + SYNDROME_IDX(mode_counter, cw_counter),
1200 0 : t[mode_counter]); move16();
1201 0 : IF (sub(deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)], t[mode_counter]) > 0)
1202 : {
1203 0 : blacklist[mode_counter] = 1; move16();
1204 0 : BREAK;
1205 : }
1206 : }
1207 : }
1208 :
1209 : /* risk analysis for mode candidate selection */
1210 0 : FOR (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1211 : {
1212 0 : dec_risk_f[mode_counter].mantissa = SIMPLE_FLOAT_1_MANTISSA; move16();
1213 0 : dec_risk_f[mode_counter].exponent = 0; move16();
1214 :
1215 0 : IF (blacklist[mode_counter] == 0)
1216 : {
1217 0 : FOR (cw_counter = 0; cw_counter < 6; cw_counter++)
1218 : {
1219 0 : dec_risk_f[mode_counter] = simple_float_mul(
1220 : dec_risk_f[mode_counter],
1221 0 : risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)]]); move16();
1222 : }
1223 :
1224 0 : IF (simple_float_cmp(dec_risk_f[mode_counter], ep_risk_thresh) <= 0)
1225 : {
1226 0 : mode_candidates[n_mode_candidates++] = mode_counter; move16();
1227 : }
1228 :
1229 0 : IF (simple_float_cmp(dec_risk_f[mode_counter], risk_min_f) < 0)
1230 : {
1231 0 : risk_min_f = dec_risk_f[mode_counter]; move16();
1232 : }
1233 : }
1234 : }
1235 0 : assert(n_mode_candidates <= 4); // suppress false gcc warning when OPTIM=3
1236 :
1237 : /* sort mode candidates by risk */
1238 0 : FOR (i = 0; i < n_mode_candidates; i++)
1239 : {
1240 0 : idx_min = i; move16();
1241 0 : val_min_f = dec_risk_f[mode_candidates[i]]; move16();
1242 :
1243 0 : FOR (j = i + 1; j < n_mode_candidates; j++)
1244 : {
1245 0 : IF (simple_float_cmp(dec_risk_f[mode_candidates[j]], val_min_f) < 0)
1246 : {
1247 0 : val_min_f = dec_risk_f[mode_candidates[j]]; move16();
1248 0 : idx_min = j; move16();
1249 : }
1250 : }
1251 :
1252 0 : IF (sub(idx_min, i) > 0)
1253 : {
1254 0 : tmp = mode_candidates[i]; move16();
1255 0 : mode_candidates[i] = mode_candidates[idx_min]; move16();
1256 0 : mode_candidates[idx_min] = tmp; move16();
1257 : }
1258 : }
1259 :
1260 : /* try out candidate modes */
1261 0 : FOR (i = 0; i < n_mode_candidates; i++)
1262 : {
1263 0 : mode = mode_candidates[i]; move16();
1264 :
1265 0 : FOR (cw_counter = 0; cw_counter < 6; cw_counter++)
1266 : {
1267 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1268 :
1269 0 : IF (deg_elp[DEG_ELP_IDX(mode, cw_counter)])
1270 : {
1271 0 : IF (rs16_factorize_elp(err_pos + ERR_POS_IDX(mode, cw_counter), elp + ELP_IDX(mode, cw_counter),
1272 : deg_elp[DEG_ELP_IDX(mode, cw_counter)], sub(codeword_length, 1)))
1273 : {
1274 : /* elp did not split into distinct linear factors or error position was out of range */
1275 0 : mode = -1; move16();
1276 0 : BREAK;
1277 : }
1278 : }
1279 : }
1280 0 : IF (mode > 0)
1281 : {
1282 : /* decodable mode with lowest risk has been found */
1283 0 : BREAK;
1284 : }
1285 : }
1286 :
1287 0 : IF (mode < 0)
1288 : {
1289 : /* no decodable mode has been found */
1290 0 : *error_report = ERROR_REPORT_BEC_MASK; move16();
1291 0 : *bfi = 1; move32();
1292 0 : mode = -1; move16();
1293 :
1294 0 : *epmr = fec_estimate_epmr_from_cw0(iobuf, t, syndromes, elp, deg_elp, err_pos, err_symb, n_codewords,
1295 : n_symb);
1296 :
1297 : Dyn_Mem_Deluxe_Out();
1298 0 : return mode;
1299 : }
1300 :
1301 : /* perform error correction */
1302 0 : cw_offset = 0; move16();
1303 0 : *error_report = 0; move16();
1304 0 : FOR (cw_counter = 0; cw_counter < 6; cw_counter++)
1305 : {
1306 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1307 :
1308 0 : IF (deg_elp[DEG_ELP_IDX(mode, cw_counter)])
1309 : {
1310 0 : rs16_calculate_errors(
1311 0 : err_symb + ERR_SYMB_IDX(mode, cw_counter), err_pos + ERR_POS_IDX(mode, cw_counter),
1312 0 : syndromes + SYNDROME_IDX(mode, cw_counter), deg_elp[DEG_ELP_IDX(mode, cw_counter)], t[mode]);
1313 :
1314 : /* correct errors and sum up number of corrected bits */
1315 0 : FOR (i = 0; i < deg_elp[DEG_ELP_IDX(mode, cw_counter)]; i++)
1316 : {
1317 0 : iobuf[err_pos[ERR_POS_IDX(mode, cw_counter) + i] + cw_offset] =
1318 0 : GF16_ADD(iobuf[err_pos[ERR_POS_IDX(mode, cw_counter) + i] + cw_offset],
1319 : err_symb[ERR_SYMB_IDX(mode, cw_counter) + i]);
1320 0 : *error_report = add(*error_report,
1321 0 : rs16_bit_count_table[err_symb[ERR_SYMB_IDX(mode, cw_counter) + i]]); move16();
1322 : }
1323 :
1324 0 : FOR (i = 0; i < mode; i ++)
1325 : {
1326 0 : IF(deg_elp[DEG_ELP_IDX(mode, cw_counter)] > i)
1327 : {
1328 0 : mode_broken[i] = 1;
1329 : }
1330 : }
1331 : }
1332 :
1333 0 : FOR (i = 0; i <= EP_SIG_POLY_DEG; i++)
1334 : {
1335 0 : iobuf[cw_offset + i] = GF16_ADD(iobuf[cw_offset + i], sig_polys[mode][i]);
1336 : }
1337 0 : cw_offset = add(cw_offset, codeword_length);
1338 : }
1339 :
1340 : /* set epmr according to risk value of cw0 */
1341 0 : epmr_dec_fail_increment = 8;
1342 :
1343 0 : IF (add(risk_table_f[mode][deg_elp[DEG_ELP_IDX(mode, 0)]].exponent, 8) <= 0)
1344 : {
1345 0 : epmr_dec_fail_increment = sub(epmr_dec_fail_increment, 4);
1346 : }
1347 0 : IF (add(risk_table_f[mode][deg_elp[DEG_ELP_IDX(mode, 0)]].exponent, 16) <= 0)
1348 : {
1349 0 : epmr_dec_fail_increment = sub(epmr_dec_fail_increment, 4);
1350 : }
1351 :
1352 0 : *epmr = cw0_get_epmr(iobuf, epmr_position) + epmr_dec_fail_increment;
1353 : }
1354 :
1355 : /* mode has been successfully detected -> now check and try to correct remaining code words*/
1356 0 : *n_pccw = fec_get_n_pccw(n_symb / 2, mode + 1, ccc_flag);
1357 0 : IF (ccc_flag == 0)
1358 : {
1359 0 : n_pccw0 = fec_get_n_pccw(n_symb / 2, mode + 1, ccc_flag);
1360 0 : *n_pccw = n_pccw0;
1361 : }
1362 : ELSE
1363 : {
1364 0 : n_pccw0 = 0;
1365 : }
1366 :
1367 0 : FOR (cw_counter = 6; cw_counter < n_codewords; cw_counter++)
1368 : {
1369 : /* usual error correction scheme: syndromes -> elp's, errors, etc. */
1370 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1371 0 : array_of_trust[n_codewords - 1 - cw_counter] = 1; move16();
1372 :
1373 0 : syndr_calc[sub(t[mode], 1)](syndromes, iobuf + cw_offset, sub(codeword_length, 1));
1374 :
1375 0 : deg_elp[0] = rs16_calculate_elp(elp, syndromes, t[mode]); move16();
1376 :
1377 0 : FOR (i = 0; i < mode; i ++)
1378 : {
1379 0 : IF(deg_elp[0] > i)
1380 : {
1381 0 : mode_broken[i] = 1;
1382 : }
1383 : }
1384 0 : IF (sub(deg_elp[0], t[mode]) > 0)
1385 : {
1386 0 : FOR (i = 0; i < 4; i ++)
1387 : {
1388 0 : mode_broken[i] = 1;
1389 : }
1390 0 : cw_offset = add(cw_offset, codeword_length);
1391 0 : IF (cw_counter < n_codewords - n_pccw0)
1392 : {
1393 0 : *error_report = ERROR_REPORT_BEC_MASK; move16();
1394 0 : mode = -1; move16();
1395 0 : *bfi = 1; move32();
1396 :
1397 0 : BREAK;
1398 : }
1399 : ELSE
1400 : {
1401 0 : *bfi = 2; move32();
1402 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0; move16();
1403 0 : CONTINUE;
1404 : }
1405 : }
1406 :
1407 0 : IF (deg_elp[0])
1408 : {
1409 0 : IF (rs16_factorize_elp(err_pos, elp, deg_elp[0], sub(codeword_length, 1)))
1410 : {
1411 0 : cw_offset = add(cw_offset, codeword_length);
1412 0 : FOR (i = 0; i < 4; i ++)
1413 : {
1414 0 : mode_broken[i] = 1;
1415 : }
1416 0 : IF (add(n_pccw0, sub(cw_counter, n_codewords)) < 0)
1417 : {
1418 0 : *error_report = ERROR_REPORT_BEC_MASK; move16();
1419 0 : mode = -1; move16();
1420 0 : *bfi = 1; move32();
1421 :
1422 0 : BREAK;
1423 : }
1424 : ELSE
1425 : {
1426 0 : *bfi = 2; move32();
1427 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0; move16();
1428 0 : CONTINUE;
1429 : }
1430 : }
1431 :
1432 0 : rs16_calculate_errors(err_symb, err_pos, syndromes, deg_elp[0], t[mode]);
1433 :
1434 : /* correct errors and sum up number of corrected bits */
1435 0 : FOR (i = 0; i < deg_elp[0]; i++)
1436 : {
1437 0 : iobuf[err_pos[i] + cw_offset] = GF16_ADD(iobuf[err_pos[i] + cw_offset], err_symb[i]);
1438 0 : *error_report = add(*error_report, rs16_bit_count_table[err_symb[i]]);
1439 : }
1440 : }
1441 0 : cw_offset = add(cw_offset, codeword_length);
1442 0 : if (add(risk_table_f[mode][deg_elp[0]].exponent, 16) > 0)
1443 : {
1444 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0; move16();
1445 : }
1446 : }
1447 :
1448 0 : *error_report &= ERROR_REPORT_BEC_MASK;
1449 0 : FOR (i = 0; i < 4; i ++)
1450 : {
1451 0 : IF (!mode_broken[i])
1452 : {
1453 0 : *error_report |= error_report_ep_ok[i];
1454 : }
1455 : }
1456 :
1457 : Dyn_Mem_Deluxe_Out();
1458 0 : IF (mode >= 0)
1459 : {
1460 0 : return add(mode, 1);
1461 : }
1462 :
1463 0 : return -1;
1464 : }
1465 :
1466 0 : FEC_STATIC void rs16_calculate_six_syndromes(UWord8 *syndromes, UWord8 *cw, int cw_poly_deg)
1467 : {
1468 : Dyn_Mem_Deluxe_In(
1469 : int i;
1470 : UWord8 buffer[15];
1471 : );
1472 :
1473 0 : assert(cw_poly_deg >= 12);
1474 :
1475 0 : FOR (i = 0; i <= cw_poly_deg; i++)
1476 : {
1477 0 : buffer[i] = cw[i]; move16();
1478 : }
1479 :
1480 0 : syndromes[0] = buffer[0]; move16();
1481 0 : syndromes[1] = buffer[0]; move16();
1482 0 : syndromes[2] = buffer[0]; move16();
1483 0 : syndromes[3] = buffer[0]; move16();
1484 0 : syndromes[4] = buffer[0]; move16();
1485 0 : syndromes[5] = buffer[0]; move16();
1486 :
1487 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32)); move16();
1488 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64)); move16();
1489 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[1], 128)); move16();
1490 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[1], 48)); move16();
1491 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[1], 96)); move16();
1492 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[1], 192)); move16();
1493 :
1494 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64)); move16();
1495 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48)); move16();
1496 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[2], 192)); move16();
1497 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[2], 80)); move16();
1498 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[2], 112)); move16();
1499 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[2], 240)); move16();
1500 :
1501 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128)); move16();
1502 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192)); move16();
1503 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[3], 160)); move16();
1504 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[3], 240)); move16();
1505 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[3], 16)); move16();
1506 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[3], 128)); move16();
1507 :
1508 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48)); move16();
1509 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80)); move16();
1510 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[4], 240)); move16();
1511 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[4], 32)); move16();
1512 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[4], 96)); move16();
1513 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[4], 160)); move16();
1514 :
1515 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96)); move16();
1516 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112)); move16();
1517 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[5], 16)); move16();
1518 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[5], 96)); move16();
1519 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[5], 112)); move16();
1520 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[5], 16)); move16();
1521 :
1522 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192)); move16();
1523 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240)); move16();
1524 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[6], 128)); move16();
1525 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[6], 160)); move16();
1526 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[6], 16)); move16();
1527 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[6], 192)); move16();
1528 :
1529 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176)); move16();
1530 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144)); move16();
1531 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[7], 192)); move16();
1532 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[7], 208)); move16();
1533 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[7], 96)); move16();
1534 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[7], 240)); move16();
1535 :
1536 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80)); move16();
1537 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32)); move16();
1538 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[8], 160)); move16();
1539 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[8], 64)); move16();
1540 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[8], 112)); move16();
1541 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[8], 128)); move16();
1542 :
1543 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160)); move16();
1544 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128)); move16();
1545 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[9], 240)); move16();
1546 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[9], 192)); move16();
1547 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[9], 16)); move16();
1548 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[9], 160)); move16();
1549 :
1550 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112)); move16();
1551 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96)); move16();
1552 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[10], 16)); move16();
1553 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[10], 112)); move16();
1554 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[10], 96)); move16();
1555 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[10], 16)); move16();
1556 :
1557 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224)); move16();
1558 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176)); move16();
1559 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[11], 128)); move16();
1560 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[11], 144)); move16();
1561 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[11], 112)); move16();
1562 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[11], 192)); move16();
1563 :
1564 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240)); move16();
1565 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160)); move16();
1566 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[12], 192)); move16();
1567 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[12], 128)); move16();
1568 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[12], 16)); move16();
1569 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[12], 240)); move16();
1570 :
1571 0 : IF (sub(cw_poly_deg, 13) >= 0)
1572 : {
1573 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208)); move16();
1574 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224)); move16();
1575 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[13], 160)); move16();
1576 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[13], 176)); move16();
1577 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[13], 96)); move16();
1578 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[13], 128)); move16();
1579 : }
1580 :
1581 0 : IF (sub(cw_poly_deg, 14) >= 0)
1582 : {
1583 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144)); move16();
1584 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208)); move16();
1585 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[14], 240)); move16();
1586 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[14], 224)); move16();
1587 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[14], 112)); move16();
1588 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[14], 160)); move16();
1589 : }
1590 :
1591 : Dyn_Mem_Deluxe_Out();
1592 0 : }
1593 :
1594 0 : FEC_STATIC void rs16_calculate_four_syndromes(UWord8 *syndromes, UWord8 *cw, int cw_poly_deg)
1595 : {
1596 : Dyn_Mem_Deluxe_In(
1597 : int i;
1598 : UWord8 buffer[15];
1599 : );
1600 :
1601 0 : assert(cw_poly_deg >= 12);
1602 :
1603 0 : FOR (i = 0; i <= cw_poly_deg; i++)
1604 : {
1605 0 : buffer[i] = cw[i]; move16();
1606 : }
1607 :
1608 0 : syndromes[0] = buffer[0]; move16();
1609 0 : syndromes[1] = buffer[0]; move16();
1610 0 : syndromes[2] = buffer[0]; move16();
1611 0 : syndromes[3] = buffer[0]; move16();
1612 :
1613 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32)); move16();
1614 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64)); move16();
1615 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[1], 128)); move16();
1616 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[1], 48)); move16();
1617 :
1618 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64)); move16();
1619 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48)); move16();
1620 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[2], 192)); move16();
1621 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[2], 80)); move16();
1622 :
1623 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128)); move16();
1624 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192)); move16();
1625 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[3], 160)); move16();
1626 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[3], 240)); move16();
1627 :
1628 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48)); move16();
1629 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80)); move16();
1630 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[4], 240)); move16();
1631 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[4], 32)); move16();
1632 :
1633 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96)); move16();
1634 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112)); move16();
1635 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[5], 16)); move16();
1636 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[5], 96)); move16();
1637 :
1638 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192)); move16();
1639 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240)); move16();
1640 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[6], 128)); move16();
1641 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[6], 160)); move16();
1642 :
1643 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176)); move16();
1644 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144)); move16();
1645 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[7], 192)); move16();
1646 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[7], 208)); move16();
1647 :
1648 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80)); move16();
1649 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32)); move16();
1650 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[8], 160)); move16();
1651 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[8], 64)); move16();
1652 :
1653 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160)); move16();
1654 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128)); move16();
1655 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[9], 240)); move16();
1656 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[9], 192)); move16();
1657 :
1658 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112)); move16();
1659 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96)); move16();
1660 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[10], 16)); move16();
1661 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[10], 112)); move16();
1662 :
1663 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224)); move16();
1664 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176)); move16();
1665 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[11], 128)); move16();
1666 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[11], 144)); move16();
1667 :
1668 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240)); move16();
1669 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160)); move16();
1670 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[12], 192)); move16();
1671 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[12], 128)); move16();
1672 :
1673 0 : IF (sub(cw_poly_deg, 13) >= 0)
1674 : {
1675 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208)); move16();
1676 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224)); move16();
1677 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[13], 160)); move16();
1678 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[13], 176)); move16();
1679 : }
1680 :
1681 0 : IF (sub(cw_poly_deg, 14) >= 0)
1682 : {
1683 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144)); move16();
1684 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208)); move16();
1685 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[14], 240)); move16();
1686 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[14], 224)); move16();
1687 : }
1688 :
1689 : Dyn_Mem_Deluxe_Out();
1690 0 : }
1691 :
1692 0 : FEC_STATIC void rs16_calculate_two_syndromes(UWord8 *syndromes, UWord8 *cw, int cw_poly_deg)
1693 : {
1694 : Dyn_Mem_Deluxe_In(
1695 : int i;
1696 : UWord8 buffer[15];
1697 : );
1698 :
1699 0 : assert(cw_poly_deg >= 12);
1700 :
1701 0 : FOR (i = 0; i <= cw_poly_deg; i++)
1702 : {
1703 0 : buffer[i] = cw[i]; move16();
1704 : }
1705 :
1706 0 : syndromes[0] = buffer[0]; move16();
1707 0 : syndromes[1] = buffer[0]; move16();
1708 :
1709 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32)); move16();
1710 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64)); move16();
1711 :
1712 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64)); move16();
1713 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48)); move16();
1714 :
1715 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128)); move16();
1716 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192)); move16();
1717 :
1718 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48)); move16();
1719 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80)); move16();
1720 :
1721 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96)); move16();
1722 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112)); move16();
1723 :
1724 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192)); move16();
1725 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240)); move16();
1726 :
1727 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176)); move16();
1728 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144)); move16();
1729 :
1730 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80)); move16();
1731 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32)); move16();
1732 :
1733 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160)); move16();
1734 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128)); move16();
1735 :
1736 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112)); move16();
1737 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96)); move16();
1738 :
1739 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224)); move16();
1740 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176)); move16();
1741 :
1742 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240)); move16();
1743 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160)); move16();
1744 :
1745 0 : IF (sub(cw_poly_deg, 13) >= 0)
1746 : {
1747 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208)); move16();
1748 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224)); move16();
1749 : }
1750 :
1751 0 : IF (sub(cw_poly_deg, 14) >= 0)
1752 : {
1753 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144)); move16();
1754 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208)); move16();
1755 : }
1756 :
1757 : Dyn_Mem_Deluxe_Out();
1758 0 : }
1759 :
1760 0 : FEC_STATIC Word8 rs16_calculate_elp(UWord8 *elp, UWord8 *syndromes, Word16 t)
1761 : /* calculates error locator polynomial vie Petterson's algorithm */
1762 : {
1763 : Dyn_Mem_Deluxe_In(
1764 : Word8 ret;
1765 : UWord8 det, det_inv, aux, all_s, *s;
1766 : UWord8 s22, s33, s44, s13, s14, s15;
1767 : UWord8 s23, s24, s25, s34, s35;
1768 : UWord8 a, b, c, d, e, f;
1769 : );
1770 :
1771 0 : ret = 0; move16();
1772 0 : all_s = 0; move16();
1773 0 : s = syndromes; move16();
1774 0 : elp[0] = 1; move16();
1775 0 : basop_memset(elp + 1, 0, 3);
1776 :
1777 0 : SWITCH (t)
1778 : {
1779 0 : case 3:
1780 : {
1781 : /* check for errors */
1782 0 : all_s = (UWord8)s_or(s[0], s_or(s[1], s_or(s[2], s_or(s[3], s_or(s[4], s[5])))));
1783 :
1784 0 : IF (all_s == 0)
1785 : {
1786 0 : BREAK;
1787 : }
1788 :
1789 : /* assume 3 errors */
1790 0 : s22 = GF16_MUL(s[1], s[1]);
1791 0 : s33 = GF16_MUL(s[2], s[2]);
1792 0 : s44 = GF16_MUL(s[3], s[3]);
1793 0 : s13 = GF16_MUL(s[0], s[2]);
1794 :
1795 0 : det = GF16_ADD(GF16_ADD(GF16_MUL(s13, s[4]), GF16_MUL(s44, s[0])),
1796 : GF16_ADD(GF16_MUL(s22, s[4]), GF16_MUL(s33, s[2])));
1797 :
1798 0 : IF (det)
1799 : {
1800 0 : det_inv = (UWord8)shl(gf16_inv_table[det], 4);
1801 :
1802 0 : s14 = GF16_MUL(s[0], s[3]);
1803 0 : s15 = GF16_MUL(s[0], s[4]);
1804 :
1805 0 : s23 = GF16_MUL(s[1], s[2]);
1806 0 : s24 = GF16_MUL(s[1], s[3]);
1807 0 : s25 = GF16_MUL(s[1], s[4]);
1808 :
1809 0 : s34 = GF16_MUL(s[2], s[3]);
1810 0 : s35 = GF16_MUL(s[2], s[4]);
1811 :
1812 0 : a = GF16_ADD(s35, s44) << 4;
1813 0 : b = GF16_ADD(s15, s33) << 4;
1814 0 : c = GF16_ADD(s13, s22) << 4;
1815 0 : d = GF16_ADD(s34, s25) << 4;
1816 0 : e = GF16_ADD(s23, s14) << 4;
1817 0 : f = GF16_ADD(s24, s33) << 4;
1818 :
1819 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(a, s[3]), GF16_MUL0(d, s[4])), GF16_MUL0(f, s[5]));
1820 0 : elp[3] = GF16_MUL0(aux, det_inv);
1821 :
1822 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(d, s[3]), GF16_MUL0(b, s[4])), GF16_MUL0(e, s[5]));
1823 0 : elp[2] = GF16_MUL0(aux, det_inv);
1824 :
1825 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(f, s[3]), GF16_MUL0(e, s[4])), GF16_MUL0(c, s[5]));
1826 0 : elp[1] = GF16_MUL0(aux, det_inv);
1827 :
1828 0 : IF (elp[3] == 0)
1829 : {
1830 0 : ret = (Word8) add(t, 1);
1831 : }
1832 : ELSE
1833 : {
1834 0 : ret = 3; move16();
1835 : }
1836 0 : BREAK;
1837 : }
1838 :
1839 : /* assume two errors */
1840 0 : det = GF16_ADD(GF16_MUL(syndromes[0], syndromes[2]), GF16_MUL(syndromes[1], syndromes[1]));
1841 :
1842 0 : IF (det)
1843 : {
1844 0 : det_inv = (UWord8)shl(gf16_inv_table[det], 4);
1845 :
1846 0 : aux = GF16_ADD(GF16_MUL(syndromes[1], syndromes[2]), GF16_MUL(syndromes[0], syndromes[3]));
1847 0 : elp[1] = GF16_MUL0(aux, det_inv);
1848 :
1849 0 : aux = GF16_ADD(GF16_MUL(syndromes[2], syndromes[2]), GF16_MUL(syndromes[1], syndromes[3]));
1850 0 : elp[2] = GF16_MUL0(aux, det_inv);
1851 :
1852 : /* check remaining LSF relations */
1853 0 : aux = (UWord8)s_or(GF16_ADD(GF16_ADD(GF16_MUL(elp[2], s[2]), GF16_MUL(elp[1], s[3])), s[4]),
1854 0 : GF16_ADD(GF16_ADD(GF16_MUL(elp[2], s[3]), GF16_MUL(elp[1], s[4])), s[5]));
1855 :
1856 0 : aux = (UWord8)s_or(aux, elp[2] == 0);
1857 :
1858 0 : IF (aux != 0)
1859 : {
1860 0 : ret = (Word8) add(t, 1);
1861 : }
1862 : ELSE
1863 : {
1864 0 : ret = 2; move16();
1865 : }
1866 0 : BREAK;
1867 : }
1868 :
1869 : /* assume one error */
1870 0 : IF (syndromes[0] != 0)
1871 : {
1872 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1873 :
1874 : /* check remaining LSF relations */
1875 0 : aux = (UWord8)s_or(s_or(GF16_ADD(GF16_MUL(elp[1], s[1]), s[2]), GF16_ADD(GF16_MUL(elp[1], s[2]), s[3])),
1876 0 : s_or(GF16_ADD(GF16_MUL(elp[1], s[3]), s[4]), GF16_ADD(GF16_MUL(elp[1], s[4]), s[5])));
1877 :
1878 0 : aux = (UWord8)s_or(aux, elp[1] == 0);
1879 :
1880 0 : IF (aux != 0)
1881 : {
1882 0 : ret = (Word8) add(t, 1);
1883 : }
1884 : ELSE
1885 : {
1886 0 : ret = 1; move16();
1887 : }
1888 0 : BREAK;
1889 : }
1890 :
1891 0 : ret = (Word8) add(t, 1);
1892 0 : BREAK;
1893 : }
1894 0 : case 2:
1895 : {
1896 0 : all_s = (UWord8)s_or(s[0], s_or(s[1], s_or(s[2], s[3])));
1897 :
1898 0 : IF (all_s == 0)
1899 : {
1900 0 : BREAK;
1901 : }
1902 :
1903 : /* assume two errors */
1904 0 : det = GF16_ADD(GF16_MUL(syndromes[0], syndromes[2]), GF16_MUL(syndromes[1], syndromes[1]));
1905 :
1906 0 : IF (det)
1907 : {
1908 0 : det_inv = (UWord8)shl(gf16_inv_table[det], 4);
1909 :
1910 0 : aux = GF16_ADD(GF16_MUL(syndromes[1], syndromes[2]), GF16_MUL(syndromes[0], syndromes[3]));
1911 0 : elp[1] = GF16_MUL0(aux, det_inv);
1912 :
1913 0 : aux = GF16_ADD(GF16_MUL(syndromes[2], syndromes[2]), GF16_MUL(syndromes[1], syndromes[3]));
1914 0 : elp[2] = GF16_MUL0(aux, det_inv);
1915 :
1916 0 : IF (elp[2] == 0)
1917 : {
1918 0 : ret = (Word8) add(t, 1);
1919 : }
1920 : ELSE
1921 : {
1922 0 : ret = 2; move16();
1923 : }
1924 0 : BREAK;
1925 : }
1926 :
1927 : /* assume one error */
1928 0 : IF (syndromes[0] != 0)
1929 : {
1930 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1931 :
1932 : /* check remaining LSF relation */
1933 0 : aux = (UWord8)s_or(GF16_ADD(GF16_MUL(elp[1], s[1]), s[2]), GF16_ADD(GF16_MUL(elp[1], s[2]), s[3]));
1934 0 : aux = (UWord8)s_or(aux, elp[1] == 0);
1935 0 : IF (aux != 0)
1936 : {
1937 0 : ret = (Word8) add(t, 1);
1938 : }
1939 : ELSE
1940 : {
1941 0 : ret = 1; move16();
1942 : }
1943 0 : BREAK;
1944 : }
1945 :
1946 0 : ret = (Word8) add(t, 1);
1947 0 : BREAK;
1948 : }
1949 0 : case 1:
1950 : {
1951 0 : all_s = (UWord8)s_or(s[0], s[1]);
1952 :
1953 0 : IF (all_s == 0)
1954 : {
1955 0 : BREAK;
1956 : }
1957 :
1958 0 : IF (syndromes[0] != 0)
1959 : {
1960 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1961 0 : IF (elp[1] == 0)
1962 : {
1963 0 : ret = (Word8) add(t, 1);
1964 : }
1965 : ELSE
1966 : {
1967 0 : ret = 1; move16();
1968 : }
1969 0 : BREAK;
1970 : }
1971 :
1972 0 : ret = (Word8) add(t, 1);
1973 0 : BREAK;
1974 : }
1975 0 : default: assert(0 && "calculating elp of this degree not implemented");
1976 : }
1977 :
1978 : Dyn_Mem_Deluxe_Out();
1979 0 : return ret;
1980 : }
1981 :
1982 0 : FEC_STATIC Word16 rs16_factorize_elp(UWord8 *err_pos, UWord8 *elp, Word16 deg_elp, Word16 max_pos)
1983 : {
1984 : Dyn_Mem_Deluxe_In(
1985 : UWord8 beta, gamma;
1986 : Word16 zeros, err_pos0, err_pos1, err_pos2, ret;
1987 : );
1988 :
1989 0 : beta = 0; move16();
1990 0 : gamma = 0; move16();
1991 0 : zeros = 0; move16();
1992 0 : ret = 0; move16();
1993 :
1994 0 : SWITCH (deg_elp)
1995 : {
1996 0 : case 0: BREAK;
1997 :
1998 0 : case 1:
1999 0 : err_pos0 = gf16_log_g[elp[1]]; move16();
2000 0 : IF (sub(err_pos0, max_pos) > 0)
2001 : {
2002 0 : ret = 1; move16();
2003 0 : BREAK;
2004 : }
2005 :
2006 0 : err_pos[0] = (UWord8)err_pos0; move16();
2007 0 : BREAK;
2008 :
2009 0 : case 2:
2010 0 : zeros = rs16_elp_deg2_table[s_or(elp[1], shl(elp[2], 4))]; move16();
2011 0 : IF (zeros == 0)
2012 : {
2013 : Dyn_Mem_Deluxe_Out();
2014 0 : return 1;
2015 : }
2016 :
2017 0 : err_pos0 = s_and(zeros, 15);
2018 0 : err_pos1 = s_and(shr(zeros, 4), 15);
2019 :
2020 0 : IF (sub(err_pos0, max_pos) > 0 || sub(err_pos1, max_pos) > 0)
2021 : {
2022 0 : ret = 1; move16();
2023 0 : BREAK;
2024 : }
2025 :
2026 0 : err_pos[0] = (UWord8)err_pos0; move16();
2027 0 : err_pos[1] = (UWord8)err_pos1; move16();
2028 0 : BREAK;
2029 :
2030 0 : case 3:
2031 : /* beta = a*a + b, gamma = a*b + c */
2032 0 : beta = GF16_ADD(GF16_MUL(elp[1], elp[1]), elp[2]);
2033 0 : gamma = GF16_ADD(GF16_MUL(elp[1], elp[2]), elp[3]);
2034 0 : zeros = rs16_elp_deg3_table[beta | gamma << 4];
2035 :
2036 0 : IF (zeros == 0)
2037 : /* elp does not split over GF(16) or has multiple zeros */
2038 : {
2039 0 : ret = 1; move16();
2040 0 : BREAK;
2041 : }
2042 :
2043 : /* remove shift from zeros */
2044 0 : err_pos0 = GF16_ADD(s_and(zeros, 15), elp[1]);
2045 0 : err_pos1 = GF16_ADD(s_and(shr(zeros, 4), 15), elp[1]);
2046 0 : err_pos2 = GF16_ADD(s_and(shr(zeros, 8), 15), elp[1]);
2047 :
2048 0 : IF (err_pos0 == 0 || err_pos1 == 0 || err_pos2 == 0)
2049 : {
2050 0 : test(); test();
2051 : Dyn_Mem_Deluxe_Out();
2052 0 : return 1;
2053 : }
2054 :
2055 0 : err_pos0 = gf16_log_g[err_pos0];
2056 0 : err_pos1 = gf16_log_g[err_pos1];
2057 0 : err_pos2 = gf16_log_g[err_pos2];
2058 :
2059 0 : IF (sub(err_pos0, max_pos) > 0 || sub(err_pos1, max_pos) > 0 || sub(err_pos2, max_pos) > 0)
2060 : {
2061 0 : test(); test();
2062 0 : ret = 1; move16();
2063 0 : BREAK;
2064 : }
2065 :
2066 0 : err_pos[0] = (UWord8)err_pos0; move16();
2067 0 : err_pos[1] = (UWord8)err_pos1; move16();
2068 0 : err_pos[2] = (UWord8)err_pos2; move16();
2069 :
2070 0 : BREAK;
2071 :
2072 0 : default: assert(0 && "invalid degree in rs16_error_locator");
2073 : }
2074 :
2075 : Dyn_Mem_Deluxe_Out();
2076 0 : return ret;
2077 : }
2078 :
2079 0 : FEC_STATIC void rs16_calculate_errors(UWord8 *err_symb, UWord8 *err_pos, UWord8 *syndromes, Word8 deg_elp, Word8 t)
2080 : {
2081 : Dyn_Mem_Deluxe_In(
2082 : UWord8 det_inv;
2083 : UWord8 x0, x1, x2;
2084 : UWord8 x0sq, x1sq, x2sq;
2085 : UWord8 c0, c1, c2;
2086 : UWord8 s0, s1, s2;
2087 : UWord8 tmp;
2088 : );
2089 :
2090 0 : assert(deg_elp <= t);
2091 : UNUSED(t);
2092 :
2093 0 : SWITCH (deg_elp)
2094 : {
2095 0 : case 0: BREAK;
2096 :
2097 0 : case 1:
2098 0 : err_symb[0] = GF16_MUL(gf16_g_pow[15 - err_pos[0]], syndromes[0]); move16();
2099 :
2100 0 : BREAK;
2101 :
2102 0 : case 2:
2103 0 : s0 = (UWord8)shl(syndromes[0], 4);
2104 0 : s1 = (UWord8)shl(syndromes[1], 4);
2105 :
2106 0 : x0 = gf16_g_pow[err_pos[0]]; move16();
2107 0 : x1 = gf16_g_pow[err_pos[1]]; move16();
2108 :
2109 0 : x0sq = GF16_MUL(x0, x0);
2110 0 : x1sq = GF16_MUL(x1, x1);
2111 :
2112 0 : tmp = GF16_ADD(GF16_MUL(x0sq, x1), GF16_MUL(x1sq, x0));
2113 0 : det_inv = (UWord8)shl(gf16_inv_table[tmp], 4);
2114 :
2115 0 : tmp = GF16_ADD(GF16_MUL0(x1sq, s0), GF16_MUL0(x1, s1));
2116 0 : err_symb[0] = GF16_MUL0(tmp, det_inv); move16();
2117 :
2118 0 : tmp = GF16_ADD(GF16_MUL0(x0sq, s0), GF16_MUL0(x0, s1));
2119 0 : err_symb[1] = GF16_MUL0(tmp, det_inv); move16();
2120 :
2121 0 : BREAK;
2122 :
2123 0 : case 3:
2124 0 : s0 = (UWord8)shl(syndromes[0], 4);
2125 0 : s1 = (UWord8)shl(syndromes[1], 4);
2126 0 : s2 = (UWord8)shl(syndromes[2], 4);
2127 :
2128 0 : x0 = gf16_g_pow[err_pos[0]]; move16();
2129 0 : x1 = gf16_g_pow[err_pos[1]]; move16();
2130 0 : x2 = gf16_g_pow[err_pos[2]]; move16();
2131 :
2132 0 : x0sq = GF16_MUL(x0, x0);
2133 0 : x1sq = GF16_MUL(x1, x1);
2134 0 : x2sq = GF16_MUL(x2, x2);
2135 :
2136 0 : tmp = GF16_MUL(GF16_ADD(x1, x0), GF16_ADD(x2, x0));
2137 0 : tmp = GF16_MUL(GF16_ADD(x2, x1), tmp);
2138 0 : det_inv = (UWord8)shl(gf16_inv_table[tmp], 4);
2139 :
2140 0 : c0 = GF16_ADD(GF16_MUL(x1, x2sq), GF16_MUL(x2, x1sq));
2141 0 : c1 = GF16_ADD(x2sq, x1sq);
2142 0 : c2 = GF16_ADD(x2, x1);
2143 :
2144 0 : err_symb[0] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2)); move16();
2145 :
2146 0 : c0 = GF16_ADD(GF16_MUL(x0, x2sq), GF16_MUL(x2, x0sq));
2147 0 : c1 = GF16_ADD(x2sq, x0sq);
2148 0 : c2 = GF16_ADD(x2, x0);
2149 :
2150 0 : err_symb[1] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2)); move16();
2151 :
2152 0 : c0 = GF16_ADD(GF16_MUL(x0, x1sq), GF16_MUL(x1, x0sq));
2153 0 : c1 = GF16_ADD(x1sq, x0sq);
2154 0 : c2 = GF16_ADD(x1, x0);
2155 :
2156 0 : err_symb[2] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2)); move16();
2157 :
2158 0 : tmp = GF16_MUL0(err_symb[0], det_inv);
2159 0 : err_symb[0] = GF16_MUL(tmp, gf16_inv_table[x0]); move16();
2160 :
2161 0 : tmp = GF16_MUL0(err_symb[1], det_inv);
2162 0 : err_symb[1] = GF16_MUL(tmp, gf16_inv_table[x1]); move16();
2163 :
2164 0 : tmp = GF16_MUL0(err_symb[2], det_inv);
2165 0 : err_symb[2] = GF16_MUL(tmp, gf16_inv_table[x2]); move16();
2166 :
2167 0 : BREAK;
2168 :
2169 0 : default: assert(0 && "method not implemented\n"); BREAK;
2170 : }
2171 :
2172 : Dyn_Mem_Deluxe_Out();
2173 0 : }
2174 :
2175 : /* hash functions for data validation */
2176 :
2177 : /* hamming distance 4 */
2178 : static const UWord32 crc14_mask[16] = {0, 17989, 35978, 51919, 71956, 89937, 103838, 119771,
2179 : 143912, 160877, 179874, 194791, 207676, 224633, 239542, 254451};
2180 :
2181 : /* hamming distance 4 */
2182 : static const UWord32 crc22_mask[16] = {0, 4788009, 9576018, 14356859, 19152036, 23933837, 28713718, 33500639,
2183 : 33650273, 38304072, 43214899, 47867674, 52775621, 57427436, 62346391, 67001278};
2184 :
2185 0 : FEC_STATIC Word16 crc1(UWord8 *data, Word16 data_size, Word16 epmr, UWord8 *hash, Word16 hash_size, Word16 check)
2186 : {
2187 : Dyn_Mem_Deluxe_In(
2188 : UWord32 const *mask;
2189 : int shift, i, fail;
2190 : UWord32 rem;
2191 : );
2192 :
2193 0 : fail = 0; move16();
2194 0 : rem = 0; move16();
2195 :
2196 0 : assert(hash_size > 0);
2197 :
2198 0 : SWITCH (hash_size)
2199 : {
2200 0 : case 2:
2201 0 : shift = 14; move16();
2202 0 : mask = crc14_mask; move32();
2203 0 : BREAK;
2204 0 : case 3:
2205 0 : shift = 22; move16();
2206 0 : mask = crc22_mask; move32();
2207 0 : BREAK;
2208 0 : default:
2209 0 : shift = 0;
2210 0 : mask = 0;
2211 0 : assert(0 && "crc hash size not implemented");
2212 : }
2213 :
2214 : /* data array contains 4-bit words */
2215 0 : FOR (i = data_size - 1; i >= 0; i--)
2216 : {
2217 0 : rem = UL_xor(UL_lshl(rem, 4), data[i]); move32();
2218 0 : rem = UL_xor(rem, mask[UL_and(UL_lshr(rem, shift), 15)]); move32();
2219 : }
2220 :
2221 0 : rem = UL_xor(UL_lshl(rem, 4), UL_lshl(epmr, 2));
2222 0 : rem = UL_xor(rem, mask[UL_and(UL_lshr(rem, shift), 15)]); move32();
2223 :
2224 0 : FOR (i = 0; i < 2 * hash_size - 1; i++)
2225 : {
2226 0 : rem = UL_lshl(rem, 4);
2227 0 : rem = UL_xor(rem, mask[UL_and(UL_lshr(rem, shift), 15)]); move32();
2228 : }
2229 :
2230 0 : rem = UL_xor(rem, UL_lshl((UWord32)epmr, shift)); move32();
2231 :
2232 0 : IF (check)
2233 : {
2234 : /* test hash value */
2235 0 : FOR (i = 0; i < 2 * hash_size; i++)
2236 : {
2237 0 : fail = s_or(fail, UL_xor(hash[i], UL_and(UL_lshr(rem, shl(i, 2)), 15))); move32();
2238 : }
2239 : }
2240 : ELSE
2241 : {
2242 : /* write hash value */
2243 0 : for (i = 0; i < 2 * hash_size; i++)
2244 : {
2245 0 : hash[i] = (UWord8)UL_and(UL_lshr(rem, shl(i, 2)), 15); move32();
2246 : }
2247 : }
2248 :
2249 : Dyn_Mem_Deluxe_Out();
2250 0 : return fail;
2251 : }
2252 :
2253 : /* hamming distance = 4 */
2254 : static const UWord32 crc16_mask[16] = {0, 107243, 190269, 214486, 289937, 380538, 428972, 469319,
2255 : 579874, 621513, 671263, 761076, 832947, 857944, 938638, 1044581};
2256 :
2257 0 : FEC_STATIC Word16 crc2(UWord8 *data, Word16 data_size, UWord8 *hash, Word16 hash_size, Word16 check)
2258 : {
2259 : Dyn_Mem_Deluxe_In(
2260 : UWord32 const *mask;
2261 : int shift, i, fail;
2262 : UWord32 rem;
2263 : );
2264 :
2265 0 : fail = 0; move16();
2266 0 : rem = 0; move16();
2267 :
2268 0 : assert(hash_size > 0);
2269 :
2270 0 : SWITCH (hash_size)
2271 : {
2272 0 : case 2:
2273 0 : shift = 16; move16();
2274 0 : mask = crc16_mask; move32();
2275 0 : BREAK;
2276 0 : default:
2277 0 : shift = 0;
2278 0 : mask = 0;
2279 0 : assert(0 && "crc hash size not implemented");
2280 : }
2281 :
2282 : /* data array contains 4-bit words */
2283 0 : FOR (i = data_size - 1; i >= 0; i--)
2284 : {
2285 0 : rem = UL_xor(UL_lshl(rem, 4), data[i]); move32();
2286 0 : rem = UL_xor(rem, mask[UL_and(UL_lshr(rem, shift), 15)]); move32();
2287 : }
2288 :
2289 0 : FOR (i = 0; i < 2 * hash_size; i++)
2290 : {
2291 0 : rem = UL_lshl(rem, 4);
2292 0 : rem = UL_xor(rem, mask[UL_and(UL_lshr(rem, shift), 15)]); move32();
2293 : }
2294 :
2295 0 : IF (check)
2296 : {
2297 : /* test hash value */
2298 0 : FOR (i = 0; i < 2 * hash_size; i++)
2299 : {
2300 0 : fail = s_or(fail, UL_xor(hash[i], UL_and(UL_lshr(rem, shl(i, 2)), 15))); move32();
2301 : }
2302 : }
2303 : ELSE
2304 : {
2305 : /* write hash value */
2306 0 : FOR (i = 0; i < 2 * hash_size; i++)
2307 : {
2308 0 : hash[i] = (UWord8)UL_and(UL_lshr(rem, shl(i, 2)), 15); move32();
2309 : }
2310 : }
2311 :
2312 : Dyn_Mem_Deluxe_Out();
2313 0 : return fail;
2314 : }
2315 :
2316 : /* simple float implementation */
2317 :
2318 0 : FEC_STATIC simple_float simple_float_mul(simple_float op1, simple_float op2)
2319 : {
2320 : Dyn_Mem_Deluxe_In(
2321 : simple_float rop;
2322 : Word32 aux;
2323 : );
2324 0 : aux = L_shr(L_mult0(op1.mantissa, op2.mantissa), 14);
2325 0 : rop.exponent = add(op1.exponent, op2.exponent);
2326 0 : IF (L_and(aux, 32768L))
2327 : {
2328 0 : aux = L_shr(aux, 1);
2329 0 : rop.exponent = add(rop.exponent, 1);
2330 : }
2331 0 : rop.mantissa = extract_l(aux);
2332 : Dyn_Mem_Deluxe_Out();
2333 0 : return rop;
2334 : }
2335 :
2336 : /* Auxiliary */
2337 :
2338 0 : FEC_STATIC Word16 simple_float_cmp(simple_float op1, simple_float op2)
2339 : /* returns 1 if op1 > op2, 0 if op1 = op2, and -1 if op1 < op2 */
2340 : {
2341 : Dyn_Mem_Deluxe_In(
2342 : Word16 rval;
2343 : Word16 mdiff;
2344 : Word16 ediff;
2345 : );
2346 :
2347 0 : rval = 0; move16();
2348 :
2349 0 : ediff = sub(op1.exponent, op2.exponent);
2350 0 : mdiff = sub(op1.mantissa, op2.mantissa);
2351 :
2352 0 : IF (ediff == 0)
2353 : {
2354 0 : if (mdiff > 0)
2355 : {
2356 0 : rval = 1;
2357 : }
2358 0 : if (mdiff < 0)
2359 : {
2360 0 : rval = -1;
2361 : }
2362 : }
2363 : ELSE
2364 : {
2365 0 : if (ediff > 0)
2366 : {
2367 0 : rval = 1;
2368 : }
2369 0 : if (ediff < 0)
2370 : {
2371 0 : rval = -1;
2372 : }
2373 : }
2374 :
2375 : Dyn_Mem_Deluxe_Out();
2376 0 : return rval;
2377 : }
2378 :
2379 :
|