blob: 4079cc02d6fd7a1b7db802ac6f40d5310eb0e687 [file] [log] [blame]
Brian Silverman84b22232019-01-25 20:29:29 -08001# pycrc -- parameterisable CRC calculation utility and C source code generator
2#
3# Copyright (c) 2017 Thomas Pircher <tehpeh-web@tty1.net>
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to
7# deal in the Software without restriction, including without limitation the
8# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9# sell copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21# IN THE SOFTWARE.
22
23
24"""
25use as follows:
26
27 import pycrc.codegen as cg
28 import pycrc.opt as opt
29 opt = opt.Options()
30 print(cg.CodeGen(opt, '', [
31 'if (a == b) {',
32 cg.CodeGen(opt, 4*' ', ['print("a equals b\\n");']),
33 '}',
34 ]))
35"""
36
37import pycrc.symtable
38import pycrc.expr as expr
39
40
41class CodeGen(object):
42 """
43 The symbol table class.
44 """
45 def __init__(self, opt, indent, content = []):
46 """
47 The class constructor.
48 """
49 self.opt = opt
50 self.sym = pycrc.symtable.SymbolTable(opt)
51 self.indent = indent
52 self.content = content
53
54 def gen(self, indent = ''):
55 """
56 Return an array of strings.
57 """
58 out = []
59 if self.indent is None:
60 indent = ''
61 else:
62 indent += self.indent
63 for item in self.content:
64 if isinstance(item, str):
65 out.append(indent + item)
66 else:
67 out += item.gen(indent)
68 return out
69
70 def __str__(self):
71 """
72 Stringify the object.
73 """
74 return '\n'.join([l.rstrip() for l in self.gen()])
75
76
77class Conditional(CodeGen):
78 """
79 A conditional block of code.
80 """
81 def __init__(self, opt, indent, condition, content):
82 """
83 The class constructor.
84 """
85 super(Conditional, self).__init__(opt, indent)
86 if condition:
87 self.content = content
88
89
90class Conditional2(CodeGen):
91 """
92 A conditional block of code with an else block.
93 """
94 def __init__(self, opt, indent, condition, content_true, content_false):
95 """
96 The class constructor.
97 """
98 super(Conditional2, self).__init__(opt, indent)
99 if condition:
100 self.content = content_true
101 else:
102 self.content = content_false
103
104
105class Comment(CodeGen):
106 """
107 A comment wrapper.
108 """
109 def __init__(self, opt, indent, content):
110 """
111 The class constructor.
112 """
113 super(Comment, self).__init__(opt, indent)
114 self.content = [
115 '/**',
116 CodeGen(opt, indent + ' * ', content),
117 ' */'
118 ]
119
120
121class ParamBlock(CodeGen):
122 """
123 Print the parameters of the model.
124 """
125 def __init__(self, opt, indent, algorithm = False):
126 """
127 The class constructor.
128 """
129 super(ParamBlock, self).__init__(opt, indent)
130 self.content = [
131 '- {0:13s} = {1}'.format('Width', self.sym['crc_width']),
132 '- {0:13s} = {1}'.format('Poly', self.sym['crc_poly']),
133 '- {0:13s} = {1}'.format('XorIn', self.sym['crc_xor_in']),
134 '- {0:13s} = {1}'.format('ReflectIn', self.sym['crc_reflect_in']),
135 '- {0:13s} = {1}'.format('XorOut', self.sym['crc_xor_out']),
136 '- {0:13s} = {1}'.format('ReflectOut', self.sym['crc_reflect_out']),
137 Conditional(opt, '', algorithm,
138 ['- {0:13s} = {1}'.format('Algorithm', self.sym['crc_algorithm'])]),
139 Conditional(opt, '', opt.slice_by > 1,
140 ['- {0:13s} = {1}'.format('SliceBy', opt.slice_by)]),
141 ]
142
143
144
145class File(CodeGen):
146 """
147 Generate the file output.
148 """
149 def __init__(self, opt, indent):
150 """
151 The class constructor.
152 """
153 super(File, self).__init__(opt, indent)
154 self.content = [
155 Comment(opt, '', [
156 '\\file',
157 'Functions and types for CRC checks.',
158 '',
159 'Generated on {datetime}'.format(**self.sym),
160 'by {program_version}, {program_url}'.format(**self.sym),
161 'using the configuration:',
162 ParamBlock(opt, ' ', algorithm = True),
163 Conditional(opt, '', opt.action == opt.action_generate_h, [
164 '',
165 'This file defines the functions {crc_init_function}(), ' \
166 '{crc_update_function}() and {crc_finalize_function}().'.format(**self.sym),
167 '',
168 'The {crc_init_function}() function returns the inital \c crc value and must be called'.format(**self.sym),
169 'before the first call to {crc_update_function}().'.format(**self.sym),
170 'Similarly, the {crc_finalize_function}() function must be called after the last call'.format(**self.sym),
171 'to {crc_update_function}(), before the \c crc is being used.'.format(**self.sym),
172 'is being used.',
173 '',
174 'The {crc_update_function}() function can be called any number of times (including zero'.format(**self.sym),
175 'times) in between the {crc_init_function}() and {crc_finalize_function}() calls.'.format(**self.sym),
176 '',
177 'This pseudo-code shows an example usage of the API:',
178 '\code{.c}',
179 Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
180 '{cfg_t} cfg = '.format(**self.sym) + '{',
181 Conditional(self.opt, 4*' ', self.opt.width is None, [
182 '0, // width',
183 ]),
184 Conditional(self.opt, 4*' ', self.opt.poly is None, [
185 '0, // poly',
186 ]),
187 Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
188 '0, // reflect_in',
189 ]),
190 Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
191 '0, // xor_in',
192 ]),
193 Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
194 '0, // reflect_out',
195 ]),
196 Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
197 '0, // xor_out',
198 ]),
199 Conditional(self.opt, 4*' ', self.opt.width is None, [
200 '',
201 '0, // crc_mask',
202 '0, // msb_mask',
203 '0, // crc_shift',
204 ]),
205 '};',
206 ]),
207 '{crc_t} crc;'.format(**self.sym),
208 'unsigned char data[MAX_DATA_LEN];',
209 'size_t data_len;',
210 '',
211 Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
212 '{crc_table_gen_function}(&cfg);'.format(**self.sym),
213 ]),
214 'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
215 'while ((data_len = read_data(data, MAX_DATA_LEN)) > 0) {',
216 CodeGen(self.opt, 4*' ', [
217 'crc = {0}({1}crc, data, data_len);'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
218 ]),
219 '}',
220 'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
221 '\endcode',
222 ]),
223 ]),
224 ]
225 if opt.action == opt.action_generate_h:
226 self.content += self._header_file()
227 elif opt.action == opt.action_generate_c:
228 self.content += self._c_file()
229 elif opt.action == opt.action_generate_c_main:
230 self.content += self._c_file() + self._main_file()
231
232 def _header_file(self):
233 """
234 Add header content.
235 """
236 out = [
237 '#ifndef {header_protection}'.format(**self.sym),
238 '#define {header_protection}'.format(**self.sym),
239 '',
240 CodeGen(self.opt, '', _includes(self.opt)),
241 '#include <stdlib.h>',
242 Conditional(self.opt, '', self.opt.c_std != 'C89',
243 ['#include <stdint.h>']),
244 Conditional(self.opt, '', _use_cfg(self.opt) and self.opt.c_std != 'C89',
245 ['#include <stdbool.h>']),
246 '',
247 '#ifdef __cplusplus',
248 'extern "C" {',
249 '#endif',
250 '', '',
251 Comment(self.opt, '', [
252 'The definition of the used algorithm.',
253 '',
254 'This is not used anywhere in the generated code, but it may be used by the',
255 'application code to call algorithm-specific code, if desired.',
256 ]),
257 '#define {0} 1'.format(_crc_algo_define(self.opt, self.sym)),
258 '', '',
259 Comment(self.opt, self.indent, [
260 'The type of the CRC values.',
261 '',
262 'This type must be big enough to contain at least {cfg_width} bits.'.format(**self.sym),
263 ]),
264 'typedef {underlying_crc_t} {crc_t};'.format(**self.sym),
265 Conditional(self.opt, '', _use_cfg(self.opt), [
266 '', '',
267 Comment(self.opt, self.indent, ['The configuration type of the CRC algorithm.']),
268 'typedef struct {',
269 Conditional(self.opt, 4*' ', self.opt.width is None,
270 ['{0:24s} {1}'.format('unsigned int width;',
271 '/*!< The width of the polynomial */')]),
272 Conditional(self.opt, 4*' ', self.opt.poly is None,
273 ['{0:24s} {1}'.format(self.sym['crc_t'] + ' poly;',
274 '/*!< The CRC polynomial */')]),
275 Conditional(self.opt, 4*' ', self.opt.reflect_in is None,
276 ['{0:24s} {1}'.format(self.sym['c_bool'] + ' reflect_in;',
277 '/*!< Whether the input shall be reflected or not */')]),
278 Conditional(self.opt, 4*' ', self.opt.xor_in is None,
279 ['{0:24s} {1}'.format(self.sym['crc_t'] + ' xor_in;',
280 '/*!< The initial value of the register */')]),
281 Conditional(self.opt, 4*' ', self.opt.reflect_out is None,
282 ['{0:24s} {1}'.format(self.sym['c_bool'] + ' reflect_out;',
283 '/*!< Whether the output shall be reflected or not */')]),
284 Conditional(self.opt, 4*' ', self.opt.xor_out is None,
285 ['{0:24s} {1}'.format(self.sym['crc_t'] + ' xor_out;',
286 '/*!< The value which shall be XOR-ed to the final CRC value */')]),
287 Conditional(self.opt, 4*' ', self.opt.width is None, [
288 '',
289 '/* internal parameters */',
290 '{0:24s} {1}'.format(self.sym['crc_t'] + ' msb_mask;', '/*!< a bitmask with the Most Significant Bit set to 1'),
291 33*' ' + 'initialise as (crc_t)1u << (width - 1) */',
292 '{0:24s} {1}'.format(self.sym['crc_t'] + ' crc_mask;', '/*!< a bitmask with all width bits set to 1'),
293 33*' ' + 'initialise as (cfg->msb_mask - 1) | cfg->msb_mask */',
294 '{0:24s} {1}'.format('unsigned int crc_shift;', '/*!< a shift count that is used when width < 8'),
295 33*' ' + 'initialise as cfg->width < 8 ? 8 - cfg->width : 0 */',
296 ]),
297 '}} {cfg_t};'.format(**self.sym),
298 ]),
299 Conditional(self.opt, '', _use_reflect_func(self.opt) and not _use_static_reflect_func(self.opt), [
300 '', '',
301 Comment(self.opt, '', [
302 'Reflect all bits of a \\a data word of \\a data_len bytes.',
303 '',
304 '\\param[in] data The data word to be reflected.',
305 '\\param[in] data_len The width of \\a data expressed in number of bits.',
306 '\\return The reflected data.'
307 ]),
308 '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
309 ]),
310 Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
311 '', '',
312 Comment(self.opt, '', [
313 'Populate the private static crc table.',
314 '',
315 '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
316 ]),
317 'void {crc_table_gen_function}(const {cfg_t} *cfg);'.format(**self.sym),
318 ]),
319 '', '',
320 Comment(self.opt, '', [
321 'Calculate the initial crc value.',
322 '',
323 Conditional(self.opt, '', _use_cfg(self.opt), [
324 '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
325 ]),
326 '\\return The initial crc value.',
327 ]),
328 Conditional2(self.opt, '', _use_constant_crc_init(self.sym), [
329 Conditional2(self.opt, '', self.opt.c_std == 'C89', [
330 '#define {crc_init_function}() ({crc_init_value})'.format(**self.sym),
331 ], [
332 'static inline {0}'.format(_crc_init_function_def(self.opt, self.sym)),
333 '{',
334 ' return {crc_init_value};'.format(**self.sym),
335 '}',
336 ]),
337 ], [
338 '{0};'.format(_crc_init_function_def(self.opt, self.sym)),
339 ]),
340 '', '',
341 Comment(self.opt, '', [
342 'Update the crc value with new data.',
343 '',
344 '\\param[in] crc The current crc value.',
345 Conditional(self.opt, '', not _use_cfg_in_crc_update(self.opt), [
346 '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
347 ]),
348 '\\param[in] data Pointer to a buffer of \\a data_len bytes.',
349 '\\param[in] data_len Number of bytes in the \\a data buffer.',
350 '\\return The updated crc value.',
351 ]),
352 '{0};'.format(_crc_update_function_def(self.opt, self.sym)),
353 '', '',
354 Comment(self.opt, '', [
355 'Calculate the final crc value.',
356 '',
357 Conditional(self.opt, '', not _use_cfg_in_finalize(self.opt), [
358 '\\param[in] cfg A pointer to an initialised {cfg_t} structure.'.format(**self.sym),
359 ]),
360 '\\param[in] crc The current crc value.',
361 '\\return The final crc value.',
362 ]),
363 Conditional2(self.opt, '', _use_inline_crc_finalize(self.opt), [
364 Conditional2(self.opt, '', self.opt.c_std == 'C89', [
365 '#define {0}(crc) ({1})'.format(self.sym['crc_finalize_function'], _crc_final_value(self.opt, self.sym)),
366 ], [
367 'static inline {0}'.format(_crc_finalize_function_def(self.opt, self.sym)),
368 '{',
369 ' return {0};'.format(_crc_final_value(self.opt, self.sym)),
370 '}',
371 ]),
372 ], [
373 '{0};'.format(_crc_finalize_function_def(self.opt, self.sym)),
374 ]),
375 '', '',
376 '#ifdef __cplusplus',
377 '} /* closing brace for extern "C" */',
378 '#endif',
379 '',
380 '#endif /* {header_protection} */'.format(**self.sym),
381 '',
382 ]
383 return out
384
385 def _c_file(self):
386 """
387 Add C file content.
388 """
389 out = [
390 CodeGen(self.opt, '', _includes(self.opt)),
391 '#include "{header_filename}" /* include the header file generated with pycrc */'.format(**self.sym),
392 '#include <stdlib.h>',
393 Conditional(self.opt, '', self.opt.c_std != 'C89', [
394 '#include <stdint.h>',
395 Conditional(self.opt, '', self.opt.undefined_crc_parameters or \
396 self.opt.algorithm == self.opt.algo_bit_by_bit or \
397 self.opt.algorithm == self.opt.algo_bit_by_bit_fast, [
398 '#include <stdbool.h>',
399 ]),
400 ]),
401 Conditional(self.opt, '', self.opt.slice_by > 1, [
402 '#include <endian.h>',
403 ]),
404 Conditional(self.opt, '', _use_reflect_func(self.opt) and _use_static_reflect_func(self.opt), [
405 '',
406 'static {crc_t} {crc_reflect_function}({crc_t} data, size_t data_len);'.format(**self.sym),
407 ]),
408 '',
409 CodeGen(self.opt, '', _crc_table(self.opt, self.sym)),
410 CodeGen(self.opt, '', _crc_reflect_function_gen(self.opt, self.sym)),
411 CodeGen(self.opt, '', _crc_init_function_gen(self.opt, self.sym)),
412 CodeGen(self.opt, '', _crc_table_gen(self.opt, self.sym)),
413 CodeGen(self.opt, '', _crc_update_function_gen(self.opt, self.sym)),
414 CodeGen(self.opt, '', _crc_finalize_function_gen(self.opt, self.sym)),
415 '',
416 ]
417 return out
418
419 def _main_file(self):
420 """
421 Add main file content.
422 """
423 out = [
424 '',
425 '',
426 CodeGen(self.opt, '', _includes(self.opt)),
427 '#include <stdio.h>',
428 '#include <getopt.h>',
429 Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
430 '#include <stdlib.h>',
431 '#include <stdio.h>',
432 '#include <ctype.h>',
433 ]),
434 Conditional(self.opt, '', self.opt.c_std != 'C89', [
435 '#include <stdbool.h>',
436 ]),
437 '#include <string.h>',
438 '',
439 'static char str[256] = "123456789";',
440 'static {c_bool} verbose = {c_false};'.format(**self.sym),
441 self._getopt_template(),
442 '',
443 '',
444 Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
445 'static void print_params(const {cfg_t} *cfg)'.format(**self.sym),
446 ], [
447 'static void print_params(void)',
448 ]),
449 '{',
450 CodeGen(self.opt, 4*' ', [
451 'char format[20];',
452 '',
453 Conditional2(self.opt, '', self.opt.c_std == 'C89', [
454 'sprintf(format, "%%-16s = 0x%%0%dlx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
455 'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
456 'printf(format, "poly", (unsigned long int){cfg_poly});'.format(**self.sym),
457 'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
458 'printf(format, "xor_in", (unsigned long int){cfg_xor_in});'.format(**self.sym),
459 'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
460 'printf(format, "xor_out", (unsigned long int){cfg_xor_out});'.format(**self.sym),
461 'printf(format, "crc_mask", (unsigned long int){cfg_mask});'.format(**self.sym),
462 'printf(format, "msb_mask", (unsigned long int){cfg_msb_mask});'.format(**self.sym),
463 ], [
464 'snprintf(format, sizeof(format), "%%-16s = 0x%%0%dllx\\n", (unsigned int)({cfg_width} + 3) / 4);'.format(**self.sym),
465 'printf("%-16s = %d\\n", "width", (unsigned int){cfg_width});'.format(**self.sym),
466 'printf(format, "poly", (unsigned long long int){cfg_poly});'.format(**self.sym),
467 'printf("%-16s = %s\\n", "reflect_in", {0});'.format(self.sym['cfg_reflect_in'] + ' ? "true": "false"' if self.opt.reflect_in is None else ('"true"' if self.opt.reflect_in else '"false"')),
468 'printf(format, "xor_in", (unsigned long long int){cfg_xor_in});'.format(**self.sym),
469 'printf("%-16s = %s\\n", "reflect_out", {0});'.format(self.sym['cfg_reflect_out'] + ' ? "true": "false"' if self.opt.reflect_out is None else ('"true"' if self.opt.reflect_out else '"false"')),
470 'printf(format, "xor_out", (unsigned long long int){cfg_xor_out});'.format(**self.sym),
471 'printf(format, "crc_mask", (unsigned long long int){cfg_mask});'.format(**self.sym),
472 'printf(format, "msb_mask", (unsigned long long int){cfg_msb_mask});'.format(**self.sym),
473 ]),
474 ]),
475 '}',
476 '',
477 '',
478 Comment(self.opt, '', [
479 'C main function.',
480 '\\param[in] argc the number of arguments in \\a argv.',
481 '\\param[in] argv a NULL-terminated array of pointers to the argument strings.',
482 '\\retval 0 on success.',
483 '\\retval >0 on error.',
484 ]),
485 'int main(int argc, char *argv[])',
486 '{',
487 CodeGen(self.opt, 4*' ', [
488 Conditional(self.opt, '', self.opt.undefined_crc_parameters, [
489 '{cfg_t} cfg = '.format(**self.sym) + '{',
490 Conditional(self.opt, 4*' ', self.opt.width is None, [
491 '0, /* width */',
492 ]),
493 Conditional(self.opt, 4*' ', self.opt.poly is None, [
494 '0, /* poly */',
495 ]),
496 Conditional(self.opt, 4*' ', self.opt.reflect_in is None, [
497 '0, /* reflect_in */',
498 ]),
499 Conditional(self.opt, 4*' ', self.opt.xor_in is None, [
500 '0, /* xor_in */',
501 ]),
502 Conditional(self.opt, 4*' ', self.opt.reflect_out is None, [
503 '0, /* reflect_out */',
504 ]),
505 Conditional(self.opt, 4*' ', self.opt.xor_out is None, [
506 '0, /* xor_out */',
507 ]),
508 Conditional(self.opt, 4*' ', self.opt.width is None, [
509 '',
510 '0, /* crc_mask */',
511 '0, /* msb_mask */',
512 '0, /* crc_shift */',
513 ]),
514 '};',
515 ]),
516 '{crc_t} crc;'.format(**self.sym),
517 '',
518 Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
519 'get_config(argc, argv, &cfg);',
520 ], [
521 'get_config(argc, argv);',
522 ]),
523 Conditional(self.opt, '', _use_crc_table_gen(self.opt), [
524 '{crc_table_gen_function}(&cfg);'.format(**self.sym),
525 ]),
526 'crc = {0}({1});'.format(self.sym['crc_init_function'], '' if _use_constant_crc_init(self.sym) else '&cfg'),
527 'crc = {0}({1}crc, (void *)str, strlen(str));'.format(self.sym['crc_update_function'], '' if _use_cfg_in_crc_update(self.opt) else '&cfg, '),
528 'crc = {0}({1}crc);'.format(self.sym['crc_finalize_function'], '' if _use_cfg_in_finalize(self.opt) else '&cfg, '),
529 '',
530 'if (verbose) {',
531 CodeGen(self.opt, 4*' ', [
532 'print_params({0});'.format('&cfg' if self.opt.undefined_crc_parameters else ''),
533 ]),
534 '}',
535 Conditional2(self.opt, '', self.opt.c_std == 'C89', [
536 'printf("0x%lx\\n", (unsigned long int)crc);',
537 ], [
538 'printf("0x%llx\\n", (unsigned long long int)crc);',
539 ]),
540 'return 0;',
541 ]),
542 '}',
543 ]
544 return out
545
546 def _getopt_template(self):
547 """
548 Add getopt functions.
549 """
550 out = [
551 Conditional(self.opt, '', self.opt.reflect_in is None or self.opt.reflect_out is None, [
552 '',
553 '',
554 'static {c_bool} atob(const char *str)'.format(**self.sym),
555 '{',
556 CodeGen(self.opt, 4*' ', [
557 'if (!str) {',
558 CodeGen(self.opt, 4*' ', [
559 'return 0;',
560 ]),
561 '}',
562 'if (isdigit(str[0])) {',
563 CodeGen(self.opt, 4*' ', [
564 'return ({c_bool})atoi(str);'.format(**self.sym),
565 ]),
566 '}',
567 'if (tolower(str[0]) == \'t\') {',
568 CodeGen(self.opt, 4*' ', [
569 'return {c_true};'.format(**self.sym),
570 ]),
571 '}',
572 'return {c_false};'.format(**self.sym),
573 ]),
574 '}',
575 ]),
576 Conditional(self.opt, '', self.opt.poly is None or self.opt.xor_in is None or self.opt.xor_out is None, [
577 '',
578 '',
579 'static crc_t xtoi(const char *str)',
580 '{',
581 CodeGen(self.opt, 4*' ', [
582 'crc_t ret = 0;',
583 '',
584 'if (!str) {',
585 CodeGen(self.opt, 4*' ', [
586 'return 0;',
587 ]),
588 '}',
589 'if (str[0] == \'0\' && tolower(str[1]) == \'x\') {',
590 CodeGen(self.opt, 4*' ', [
591 'str += 2;',
592 'while (*str) {',
593 CodeGen(self.opt, 4*' ', [
594 'if (isdigit(*str))',
595 CodeGen(self.opt, 4*' ', [
596 'ret = 16 * ret + *str - \'0\';',
597 ]),
598 'else if (isxdigit(*str))',
599 CodeGen(self.opt, 4*' ', [
600 'ret = 16 * ret + tolower(*str) - \'a\' + 10;',
601 ]),
602 'else',
603 CodeGen(self.opt, 4*' ', [
604 'return ret;',
605 ]),
606 'str++;',
607 ]),
608 '}',
609 ]),
610 '} else if (isdigit(*str)) {',
611 CodeGen(self.opt, 4*' ', [
612 'while (*str) {',
613 CodeGen(self.opt, 4*' ', [
614 'if (isdigit(*str))',
615 CodeGen(self.opt, 4*' ', [
616 'ret = 10 * ret + *str - \'0\';',
617 ]),
618 'else',
619 CodeGen(self.opt, 4*' ', [
620 'return ret;',
621 ]),
622 'str++;',
623 ]),
624 '}',
625 ]),
626 '}',
627 'return ret;',
628 ]),
629 '}',
630 ]),
631 '',
632 '',
633 Conditional2(self.opt, '', self.opt.undefined_crc_parameters, [
634 'static int get_config(int argc, char *argv[], {cfg_t} *cfg)'.format(**self.sym),
635 ], [
636 'static int get_config(int argc, char *argv[])',
637 ]),
638 '{',
639 CodeGen(self.opt, 4*' ', [
640 'int c;',
641 'int option_index;',
642 'static struct option long_options[] = {',
643 CodeGen(self.opt, 4*' ', [
644 Conditional(self.opt, '', self.opt.width is None, [
645 '{"width", 1, 0, \'w\'},',
646 ]),
647 Conditional(self.opt, '', self.opt.poly is None, [
648 '{"poly", 1, 0, \'p\'},',
649 ]),
650 Conditional(self.opt, '', self.opt.reflect_in is None, [
651 '{"reflect-in", 1, 0, \'n\'},',
652 ]),
653 Conditional(self.opt, '', self.opt.xor_in is None, [
654 '{"xor-in", 1, 0, \'i\'},',
655 ]),
656 Conditional(self.opt, '', self.opt.reflect_out is None, [
657 '{"reflect-out", 1, 0, \'u\'},',
658 ]),
659 Conditional(self.opt, '', self.opt.xor_out is None, [
660 '{"xor-out", 1, 0, \'o\'},',
661 ]),
662 '{"verbose", 0, 0, \'v\'},',
663 '{"check-string", 1, 0, \'s\'},',
664 Conditional(self.opt, '', self.opt.width is None, [
665 '{"table-idx-with", 1, 0, \'t\'},',
666 ]),
667 '{0, 0, 0, 0}',
668 ]),
669 '};',
670 '',
671 'while (1) {',
672 CodeGen(self.opt, 4*' ', [
673 'option_index = 0;',
674 '',
675 'c = getopt_long(argc, argv, "w:p:n:i:u:o:s:vt", long_options, &option_index);',
676 'if (c == -1)',
677 CodeGen(self.opt, 4*' ', [
678 'break;',
679 ]),
680 '',
681 'switch (c) {',
682 CodeGen(self.opt, 4*' ', [
683 'case 0:',
684 CodeGen(self.opt, 4*' ', [
685 'printf("option %s", long_options[option_index].name);',
686 'if (optarg)',
687 CodeGen(self.opt, 4*' ', [
688 'printf(" with arg %s", optarg);',
689 ]),
690 'printf("\\n");',
691 'break;',
692 ]),
693 Conditional(self.opt, '', self.opt.width is None, [
694 'case \'w\':',
695 CodeGen(self.opt, 4*' ', [
696 'cfg->width = atoi(optarg);',
697 'break;',
698 ]),
699 ]),
700 Conditional(self.opt, '', self.opt.poly is None, [
701 'case \'p\':',
702 CodeGen(self.opt, 4*' ', [
703 'cfg->poly = xtoi(optarg);',
704 'break;',
705 ]),
706 ]),
707 Conditional(self.opt, '', self.opt.reflect_in is None, [
708 'case \'n\':',
709 CodeGen(self.opt, 4*' ', [
710 'cfg->reflect_in = atob(optarg);',
711 'break;',
712 ]),
713 ]),
714 Conditional(self.opt, '', self.opt.xor_in is None, [
715 'case \'i\':',
716 CodeGen(self.opt, 4*' ', [
717 'cfg->xor_in = xtoi(optarg);',
718 'break;',
719 ]),
720 ]),
721 Conditional(self.opt, '', self.opt.reflect_out is None, [
722 'case \'u\':',
723 CodeGen(self.opt, 4*' ', [
724 'cfg->reflect_out = atob(optarg);',
725 'break;',
726 ]),
727 ]),
728 Conditional(self.opt, '', self.opt.xor_out is None, [
729 'case \'o\':',
730 CodeGen(self.opt, 4*' ', [
731 'cfg->xor_out = xtoi(optarg);',
732 'break;',
733 ]),
734 ]),
735 'case \'s\':',
736 CodeGen(self.opt, 4*' ', [
737 'memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));',
738 'str[sizeof(str) - 1] = \'\\0\';',
739 'break;',
740 ]),
741 'case \'v\':',
742 CodeGen(self.opt, 4*' ', [
743 'verbose = {c_true};'.format(**self.sym),
744 'break;',
745 ]),
746 Conditional(self.opt, '', self.opt.width is None, [
747 'case \'t\':',
748 CodeGen(self.opt, 4*' ', [
749 '/* ignore --table_idx_width option */',
750 'break;',
751 ]),
752 ]),
753 'case \'?\':',
754 CodeGen(self.opt, 4*' ', [
755 'return -1;',
756 ]),
757 'case \':\':',
758 CodeGen(self.opt, 4*' ', [
759 'fprintf(stderr, "missing argument to option %c\\n", c);',
760 'return -1;',
761 ]),
762 'default:',
763 CodeGen(self.opt, 4*' ', [
764 'fprintf(stderr, "unhandled option %c\\n", c);',
765 'return -1;',
766 ]),
767 ]),
768 '}',
769 ]),
770 '}',
771 Conditional(self.opt, '', self.opt.width is None, [
772 'cfg->msb_mask = (crc_t)1u << (cfg->width - 1);',
773 'cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask;',
774 'cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0;',
775 ]),
776 '',
777 Conditional(self.opt, '', self.opt.poly is None, [
778 'cfg->poly &= {cfg_mask};'.format(**self.sym),
779 ]),
780 Conditional(self.opt, '', self.opt.xor_in is None, [
781 'cfg->xor_in &= {cfg_mask};'.format(**self.sym),
782 ]),
783 Conditional(self.opt, '', self.opt.xor_out is None, [
784 'cfg->xor_out &= {cfg_mask};'.format(**self.sym),
785 ]),
786 'return 0;',
787 ]),
788 '}',
789 ]
790 return CodeGen(self.opt, '', out)
791
792
793def _includes(opt):
794 """
795 Return the #include directives for the user-defined list of include files.
796 """
797 includes = []
798 if opt.include_files is not None and len(opt.include_files) > 0:
799 for include_file in opt.include_files:
800 if include_file[0] == '"' or include_file[0] == '<':
801 includes.append('#include {0}'.format(include_file))
802 else:
803 includes.append('#include "{0}"'.format(include_file))
804 return includes
805
806
807def _crc_algo_define(opt, sym):
808 """
809 Get the the identifier for header files.
810 """
811 name = sym['crc_algorithm'].upper().replace('-', '_')
812 return 'CRC_ALGO_' + name
813
814
815def _use_cfg(opt):
816 """
817 Return True if a cfg_t structure is to be used.
818 """
819 return opt.undefined_crc_parameters
820
821
822def _use_constant_crc_init(sym):
823 """
824 Return True if the inintial value is constant.
825 """
826 return sym['crc_init_value'] is not None
827
828
829def _use_reflect_func(opt):
830 """
831 Return True if the reflect function is to be used.
832 """
833 if opt.reflect_out == None or opt.reflect_in == None:
834 return True
835 elif opt.algorithm == opt.algo_table_driven:
836 if opt.reflect_in != opt.reflect_out:
837 return True
838 elif opt.algorithm == opt.algo_bit_by_bit:
839 if opt.reflect_in:
840 return True
841 if opt.reflect_out:
842 return True
843 elif opt.algorithm == opt.algo_bit_by_bit_fast:
844 if opt.reflect_in:
845 return True
846 if opt.reflect_out:
847 return True
848 return False
849
850
851def _use_static_reflect_func(opt):
852 """
853 Whether a static reflect function is to be used.
854 """
855 if opt.algorithm == opt.algo_table_driven:
856 return False
857 elif opt.reflect_out is not None and opt.algorithm == opt.algo_bit_by_bit_fast:
858 return False
859 else:
860 return True
861
862
863def _use_crc_table_gen(opt):
864 """
865 Return True if the table generator function is to be generated.
866 """
867 if opt.algorithm == opt.algo_table_driven:
868 return opt.width is None or opt.poly is None or opt.reflect_in is None
869 else:
870 return False
871
872
873def _crc_init_function_def(opt, sym):
874 """
875 The definition for the init function.
876 """
877 if _use_constant_crc_init(sym):
878 return '{crc_t} {crc_init_function}(void)'.format(**sym)
879 else:
880 return '{crc_t} {crc_init_function}(const {cfg_t} *cfg)'.format(**sym)
881
882
883def _use_cfg_in_crc_update(opt):
884 """
885 Return True if the update function uses the cfg_t parameter.
886 """
887 if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
888 if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
889 return True
890 elif opt.algorithm == opt.algo_table_driven:
891 if opt.width is not None and opt.reflect_in is not None:
892 return True
893 return False
894
895
896def _crc_update_function_def(opt, sym):
897 """
898 The definition of the update function.
899 """
900 if _use_cfg_in_crc_update(opt):
901 return '{crc_t} {crc_update_function}({crc_t} crc, const void *data, size_t data_len)'.format(**sym)
902 else:
903 return '{crc_t} {crc_update_function}(const {cfg_t} *cfg, {crc_t} crc, const void *data, size_t data_len)'.format(**sym)
904
905
906def _use_cfg_in_finalize(opt):
907 """
908 Return True if the cfg_t parameter is used in the finalize function.
909 """
910 if opt.algorithm == opt.algo_bit_by_bit:
911 if opt.width is not None and opt.poly is not None and opt.reflect_out is not None and opt.xor_out is not None:
912 return True
913 elif opt.algorithm == opt.algo_bit_by_bit_fast:
914 if opt.width is not None and opt.reflect_out is not None and opt.xor_out is not None:
915 return True
916 elif opt.algorithm == opt.algo_table_driven:
917 if opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None:
918 return True
919 return False
920
921
922def _use_inline_crc_finalize(opt):
923 """
924 Return True if the init function can be inlined.
925 """
926 if opt.algorithm in set([opt.algo_bit_by_bit_fast, opt.algo_table_driven]) and \
927 (opt.width is not None and opt.reflect_in is not None and opt.reflect_out is not None and opt.xor_out is not None):
928 return True
929 else:
930 return False
931
932
933def _use_constant_crc_table(opt):
934 """
935 Return True is the CRC table is constant.
936 """
937 if opt.width is not None and opt.poly is not None and opt.reflect_in is not None:
938 return True
939 else:
940 return False
941
942
943def _crc_finalize_function_def(opt, sym):
944 """
945 The definition of the finalize function.
946 """
947 if _use_cfg_in_finalize(opt):
948 return '{crc_t} {crc_finalize_function}({crc_t} crc)'.format(**sym)
949 else:
950 return '{crc_t} {crc_finalize_function}(const {cfg_t} *cfg, {crc_t} crc)'.format(**sym)
951
952
953def _crc_final_value(opt, sym):
954 """
955 The return value for the finalize function.
956 """
957 if opt.algorithm == opt.algo_table_driven:
958 if opt.reflect_in == opt.reflect_out:
959 return expr.Xor('crc', sym['crc_xor_out']).simplify()
960 else:
961 reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
962 return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
963 elif opt.reflect_out:
964 reflect_fun = expr.FunctionCall(sym['crc_reflect_function'], ['crc', sym['crc_width']])
965 return expr.Xor(reflect_fun, sym['crc_xor_out']).simplify()
966 else:
967 return expr.Xor('crc', sym['crc_xor_out']).simplify()
968
969
970def _crc_table(opt, sym):
971 """
972 Return the code for the CRC table or the generator function.
973 """
974 if opt.algorithm != opt.algo_table_driven:
975 return []
976 return [
977 '', '',
978 Comment(opt, '', [
979 'Static table used for the table_driven implementation.',
980 Conditional(opt, '', opt.undefined_crc_parameters, [
981 'Must be initialised with the {crc_table_gen_function} function.'.format(**sym),
982 ]),
983 ]),
984 Conditional2(opt, '', _use_constant_crc_table(opt), [
985 Conditional2(opt, '', opt.slice_by > 1, [
986 'static const {crc_t} crc_table[{crc_slice_by}][{crc_table_width}] = {crc_table_init};'.format(**sym),
987 ], [
988 'static const {crc_t} crc_table[{crc_table_width}] = {crc_table_init};'.format(**sym),
989 ]),
990 ], [
991 'static {crc_t} crc_table[{crc_table_width}];'.format(**sym),
992 ]),
993 ]
994
995
996def _crc_table_gen(opt, sym):
997 """
998 Return the code for the CRC table or the generator function.
999 """
1000 if opt.algorithm != opt.algo_table_driven or _use_constant_crc_table(opt):
1001 return []
1002 return [
1003 '', '',
1004 'void {crc_table_gen_function}(const {cfg_t} *cfg)'.format(**sym),
1005 '{',
1006 CodeGen(opt, 4*' ', [
1007 '{crc_t} crc;'.format(**sym),
1008 'unsigned int i, j;',
1009 '',
1010 'for (i = 0; i < {cfg_table_width}; i++) '.format(**sym) + '{',
1011 CodeGen(opt, 4*' ', [
1012 Conditional2(opt, '', opt.reflect_in is None, [
1013 'if (cfg->reflect_in) {',
1014 CodeGen(opt, 4*' ', [
1015 'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
1016 ]),
1017 '} else {',
1018 CodeGen(opt, 4*' ', [
1019 'crc = i;',
1020 ]),
1021 '}',
1022 ], [
1023 Conditional2(opt, '', opt.reflect_in, [
1024 'crc = {crc_reflect_function}(i, {cfg_table_idx_width});'.format(**sym),
1025 ], [
1026 'crc = i;',
1027 ]),
1028 ]),
1029 'crc <<= {0};'.format(expr.Parenthesis(expr.Add(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width']), sym['cfg_shift'])).simplify()),
1030 'for (j = 0; j < {cfg_table_idx_width}; j++) '.format(**sym) + '{',
1031 CodeGen(opt, 4*' ', [
1032 'if (crc & {cfg_msb_mask_shifted}) '.format(**sym) + '{',
1033 CodeGen(opt, 4*' ', [
1034 'crc = {0};'.format(expr.Xor(expr.Parenthesis(expr.Shl('crc', 1)), sym['cfg_poly_shifted']).simplify()),
1035 ]),
1036 '} else {',
1037 CodeGen(opt, 4*' ', [
1038 'crc = crc << 1;',
1039 ]),
1040 '}',
1041 ]),
1042 '}',
1043 Conditional(opt, '', opt.reflect_in is None, [
1044 'if (cfg->reflect_in) {',
1045 Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
1046 'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
1047 ], [
1048 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1049 ]),
1050 '}',
1051 ]),
1052 Conditional(opt, '', opt.reflect_in, [
1053 Conditional2(opt, 4*' ', sym.tbl_shift is None or sym.tbl_shift > 0, [
1054 'crc = {0};'.format(expr.Shl(expr.FunctionCall(sym['crc_reflect_function'], [expr.Shr('crc', sym['cfg_shift']), sym['cfg_width']]), sym['cfg_shift']).simplify()),
1055 ], [
1056 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1057 ]),
1058 ]),
1059 'crc_table[i] = {0};'.format(expr.Shr(expr.Parenthesis(expr.And('crc', sym['cfg_mask_shifted'])), sym['cfg_shift'])),
1060 ]),
1061 '}',
1062 ]),
1063 '}',
1064 ]
1065
1066
1067def _crc_reflect_function_gen(opt, sym):
1068 """
1069 Return the code for the reflect functon.
1070 """
1071 if not _use_reflect_func(opt):
1072 return []
1073 if not (opt.reflect_in is None or opt.reflect_in or \
1074 opt.reflect_out is None or opt.reflect_out):
1075 return []
1076 return [
1077 '', '',
1078 '{crc_t} {crc_reflect_function}({crc_t} data, size_t data_len)'.format(**sym),
1079 '{',
1080 CodeGen(opt, 4*' ', [
1081 'unsigned int i;',
1082 '{crc_t} ret;'.format(**sym),
1083 '',
1084 'ret = data & 0x01;',
1085 'for (i = 1; i < data_len; i++) {',
1086 CodeGen(opt, 4*' ', [
1087 'data >>= 1;',
1088 'ret = (ret << 1) | (data & 0x01);',
1089 ]),
1090 '}',
1091 'return ret;',
1092 ]),
1093 '}',
1094 ]
1095
1096
1097def _crc_init_function_gen(opt, sym):
1098 """
1099 Return the code for the init function.
1100 """
1101 if _use_constant_crc_init(sym):
1102 return []
1103 out = [
1104 '', '',
1105 _crc_init_function_def(opt, sym),
1106 '{',
1107 CodeGen(opt, 4*' ', [
1108 Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit, [
1109 'unsigned int i;',
1110 '{c_bool} bit;'.format(**sym),
1111 '{crc_t} crc = {cfg_xor_in};'.format(**sym),
1112 'for (i = 0; i < {cfg_width}; i++) '.format(**sym) + '{',
1113 CodeGen(opt, 4*' ', [
1114 'bit = crc & 0x01;',
1115 'if (bit) {',
1116 CodeGen(opt, 4*' ', [
1117 'crc = ((crc ^ {cfg_poly}) >> 1) | {cfg_msb_mask};'.format(**sym),
1118 ]),
1119 '} else {',
1120 CodeGen(opt, 4*' ', [
1121 'crc >>= 1;',
1122 ]),
1123 '}',
1124 ]),
1125 '}',
1126 'return crc & {cfg_mask};'.format(**sym),
1127 ]),
1128 Conditional(opt, '', opt.algorithm == opt.algo_bit_by_bit_fast, [
1129 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
1130 ]),
1131 Conditional(opt, '', opt.algorithm == opt.algo_table_driven, [
1132 Conditional2(opt, '', opt.reflect_in is None, [
1133 'if ({cfg_reflect_in}) '.format(**sym) + '{',
1134 CodeGen(opt, 4*' ', [
1135 'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
1136 ]),
1137 '} else {',
1138 CodeGen(opt, 4*' ', [
1139 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
1140 ]),
1141 '}',
1142 ], [
1143 Conditional2(opt, '', opt.algorithm == opt.reflect_in, [
1144 'return {crc_reflect_function}({cfg_xor_in} & {cfg_mask}, {cfg_width});'.format(**sym),
1145 ], [
1146 'return {cfg_xor_in} & {cfg_mask};'.format(**sym),
1147 ]),
1148 ]),
1149 ]),
1150 ]),
1151 '}',
1152 ]
1153 return out
1154
1155
1156def _crc_update_function_gen(opt, sym):
1157 """
1158 Return the code for the update function.
1159 """
1160 out = [
1161 '', '',
1162 _crc_update_function_def(opt, sym),
1163 '{',
1164 CodeGen(opt, 4*' ', [ 'const unsigned char *d = (const unsigned char *)data;' ]),
1165 ]
1166 if opt.algorithm == opt.algo_bit_by_bit:
1167 out += [
1168 CodeGen(opt, 4*' ', [
1169 'unsigned int i;',
1170 '{c_bool} bit;'.format(**sym),
1171 'unsigned char c;',
1172 '',
1173 'while (data_len--) {',
1174 Conditional2(opt, 4*' ', opt.reflect_in is None, [
1175 'if (' + sym['cfg_reflect_in'] + ') {',
1176 CodeGen(opt, 4*' ', [
1177 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
1178 ]),
1179 '} else {',
1180 CodeGen(opt, 4*' ', [
1181 'c = *d++;',
1182 ]),
1183 '}',
1184 ], [
1185 Conditional2(opt, '', opt.reflect_in, [
1186 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
1187 ], [
1188 'c = *d++;',
1189 ]),
1190 ]),
1191
1192 CodeGen(opt, 4*' ', [
1193 'for (i = 0; i < 8; i++) {',
1194 CodeGen(opt, 4*' ', [
1195 Conditional2(opt, '', opt.c_std == 'C89', [
1196 'bit = !!(crc & {cfg_msb_mask});'.format(**sym),
1197 ], [
1198 'bit = crc & {cfg_msb_mask};'.format(**sym),
1199 ]),
1200 'crc = (crc << 1) | ((c >> (7 - i)) & 0x01);',
1201 'if (bit) {',
1202 CodeGen(opt, 4*' ', [
1203 'crc ^= {cfg_poly};'.format(**sym),
1204 ]),
1205 '}',
1206 ]),
1207 '}',
1208 'crc &= {cfg_mask};'.format(**sym),
1209 ]),
1210 '}',
1211 'return crc & {cfg_mask};'.format(**sym),
1212 ]),
1213 ]
1214
1215 if opt.algorithm == opt.algo_bit_by_bit_fast:
1216 out += [
1217 CodeGen(opt, 4*' ', [
1218 'unsigned int i;',
1219 '{c_bool} bit;'.format(**sym),
1220 'unsigned char c;',
1221 '',
1222 'while (data_len--) {',
1223 CodeGen(opt, 4*' ', [
1224 Conditional2(opt, '', opt.reflect_in == None, [
1225 'if (' + sym['cfg_reflect_in'] + ') {',
1226 CodeGen(opt, 4*' ', [
1227 'c = {crc_reflect_function}(*d++, 8);'.format(**sym),
1228 ]),
1229 '} else {',
1230 CodeGen(opt, 4*' ', [
1231 'c = *d++;',
1232 ]),
1233 '}',
1234 ], [
1235 'c = *d++;',
1236 ]),
1237 Conditional2(opt, '', opt.reflect_in, [
1238 'for (i = 0x01; i & 0xff; i <<= 1) {',
1239 ], [
1240 'for (i = 0x80; i > 0; i >>= 1) {',
1241 ]),
1242 CodeGen(opt, 4*' ', [
1243 Conditional2(opt, '', opt.c_std == 'C89', [
1244 'bit = !!({0});'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
1245 ], [
1246 'bit = {0};'.format(expr.And('crc', sym['cfg_msb_mask']).simplify()),
1247 ]),
1248 'if (c & i) {',
1249 CodeGen(opt, 4*' ', [
1250 'bit = !bit;',
1251 ]),
1252 '}',
1253 'crc <<= 1;',
1254 'if (bit) {',
1255 CodeGen(opt, 4*' ', [
1256 'crc ^= {cfg_poly};'.format(**sym),
1257 ]),
1258 '}',
1259 ]),
1260 '}',
1261 'crc &= {cfg_mask};'.format(**sym)
1262 ]),
1263 '}',
1264 'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
1265 ]),
1266 ]
1267
1268 if opt.algorithm == opt.algo_table_driven:
1269 out += [
1270 CodeGen(opt, 4*' ', [
1271 'unsigned int tbl_idx;',
1272 '',
1273 Conditional2(opt, '', opt.reflect_in == None, [
1274 'if (cfg->reflect_in) {',
1275 CodeGen(opt, 4*' ', [
1276 'while (data_len--) {',
1277 CodeGen(opt, 4*' ', [
1278 _crc_table_core_algorithm_reflected(opt, sym),
1279 'd++;',
1280 ]),
1281 '}',
1282 ]),
1283 '} else {',
1284 CodeGen(opt, 4*' ', [
1285 'while (data_len--) {',
1286 CodeGen(opt, 4*' ', [
1287 _crc_table_core_algorithm_nonreflected(opt, sym),
1288 'd++;',
1289 ]),
1290 '}',
1291 ]),
1292 '}',
1293 ], [
1294 Conditional(opt, '', opt.slice_by > 1, [
1295 '/* Align to a multiple of {crc_slice_by} bytes */'.format(**sym),
1296 'while (data_len && (((uintptr_t)(const void *)d) % {crc_slice_by} != 0))'.format(**sym) + ' {',
1297 CodeGen(opt, 4*' ', [
1298 _crc_table_core_algorithm(opt, sym),
1299 'data_len--;',
1300 ]),
1301 '}',
1302 '',
1303 _crc_table_slice_by_algorithm(opt, sym),
1304 '/* Remaining bytes with the standard algorithm */',
1305 'd = (const unsigned char *)d32;',
1306 ]),
1307 'while (data_len--) {',
1308 CodeGen(opt, 4*' ', [
1309 _crc_table_core_algorithm(opt, sym),
1310 ]),
1311 '}',
1312 ]),
1313 'return {0};'.format(expr.And('crc', sym['cfg_mask']).simplify()),
1314 ]),
1315 ]
1316 out += [
1317 '}',
1318 ]
1319 return out
1320
1321
1322
1323def _crc_finalize_function_gen(opt, sym):
1324 """
1325 Return the code for the finalize function.
1326 """
1327 if _use_inline_crc_finalize(opt):
1328 return []
1329 out = [
1330 '', '',
1331 _crc_finalize_function_def(opt, sym),
1332 '{',
1333 ]
1334 if opt.algorithm in set([opt.algo_bit_by_bit, opt.algo_bit_by_bit_fast]):
1335 out += [
1336 Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit, [
1337 'unsigned int i;',
1338 '{c_bool} bit;'.format(**sym),
1339 '',
1340 'for (i = 0; i < ' + sym['cfg_width'] + '; i++) {',
1341 CodeGen(opt, 4*' ', [
1342 Conditional2(opt, '', opt.c_std == 'C89', [
1343 'bit = !!(crc & {cfg_msb_mask});'.format(**sym)
1344 ], [
1345 'bit = crc & {cfg_msb_mask};'.format(**sym),
1346 ]),
1347 'crc <<= 1;',
1348 'if (bit) {',
1349 CodeGen(opt, 4*' ', [
1350 'crc ^= {cfg_poly};'.format(**sym),
1351 ]),
1352 '}',
1353 ]),
1354 '}',
1355 Conditional(opt, '', opt.reflect_out is None, [
1356 'if (' + sym['cfg_reflect_out'] + ') {',
1357 CodeGen(opt, 4*' ', [
1358 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1359 ]),
1360 '}',
1361 ]),
1362 Conditional(opt, '', opt.reflect_out, [
1363 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1364 ]),
1365 ]),
1366
1367 Conditional(opt, 4*' ', opt.algorithm == opt.algo_bit_by_bit_fast, [
1368 Conditional(opt, '', opt.reflect_out is None, [
1369 'if (' + sym['cfg_reflect_out'] + ') {',
1370 CodeGen(opt, 4*' ', [
1371 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1372 ]),
1373 '}',
1374 ]),
1375 Conditional(opt, '', opt.reflect_out, [
1376 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1377 ]),
1378 ]),
1379 ]
1380
1381 if opt.algorithm == opt.algo_table_driven:
1382 if opt.reflect_in is None or opt.reflect_out is None:
1383 if opt.reflect_in is None and opt.reflect_out is None:
1384 cond = 'cfg->reflect_in != cfg->reflect_out'
1385 elif opt.reflect_out is None:
1386 cond = '!' if opt.reflect_in else '' + 'cfg->reflect_out'
1387 else:
1388 cond = '!' if opt.reflect_out else '' + 'cfg->reflect_in'
1389 out += [
1390 CodeGen(opt, 4*' ', [
1391 'if (' + cond + ') {',
1392 CodeGen(opt, 4*' ', [
1393 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1394 ]),
1395 '}',
1396 ]),
1397 ]
1398 elif opt.reflect_in != opt.reflect_out:
1399 out += [
1400 'crc = {crc_reflect_function}(crc, {cfg_width});'.format(**sym),
1401 ]
1402 out += [
1403 CodeGen(opt, 4*' ', [
1404 'return {0};'.format(expr.And(expr.Parenthesis(expr.Xor('crc', sym['cfg_xor_out'])), sym['cfg_mask']).simplify()),
1405 ]),
1406 '}',
1407 ]
1408 return out
1409
1410def _crc_table_core_algorithm(opt, sym):
1411 """
1412 Return the core of the table-driven algorithm.
1413 """
1414 out = []
1415 out += [
1416 Conditional2(opt, '', opt.reflect_in, [
1417 _crc_table_core_algorithm_reflected(opt, sym),
1418 ], [
1419 _crc_table_core_algorithm_nonreflected(opt, sym),
1420 ]),
1421 'd++;',
1422 ]
1423 return CodeGen(opt, '', out)
1424
1425def _crc_table_core_algorithm_reflected(opt, sym):
1426 """
1427 Return the core loop of the table-driven algorithm, reflected variant.
1428 """
1429 out = []
1430 if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
1431 crc_xor_expr = '0'
1432 else:
1433 crc_xor_expr = '(crc >> {cfg_table_idx_width})'.format(**sym)
1434
1435 if opt.tbl_idx_width == 8:
1436 if opt.slice_by > 1:
1437 crc_lookup = 'crc_table[0][tbl_idx]'
1438 else:
1439 crc_lookup = 'crc_table[tbl_idx]'
1440 out += [
1441 Conditional2(opt, '', opt.width is None or opt.width > 8, [
1442 'tbl_idx = (crc ^ *d) & {crc_table_mask};'.format(**sym),
1443 ], [
1444 'tbl_idx = crc ^ *d;',
1445 ]),
1446 'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, expr.Parenthesis(expr.Shr('crc', sym['cfg_table_idx_width'])))), sym['cfg_mask']).simplify()),
1447 ]
1448 else:
1449 crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
1450 for i in range(8 // opt.tbl_idx_width):
1451 out += [
1452 'tbl_idx = {0};'.format(expr.Xor('crc', expr.Parenthesis(expr.Shr('*d', expr.Parenthesis(expr.Mul(i, sym['cfg_table_idx_width']))))).simplify()),
1453 'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify())
1454 ]
1455 return CodeGen(opt, '', out)
1456
1457def _crc_table_core_algorithm_nonreflected(opt, sym):
1458 """
1459 Return the core loop of the table-driven algorithm, non-reflected variant.
1460 """
1461 out = []
1462 if opt.width == None:
1463 crc_shifted_right = expr.Parenthesis(expr.Shr('crc', expr.Parenthesis(expr.Sub(sym['cfg_width'], sym['cfg_table_idx_width'])))).simplify()
1464 elif opt.width < 8:
1465 shift_val = opt.width - opt.tbl_idx_width
1466 if shift_val < 0:
1467 crc_shifted_right = expr.Parenthesis(expr.Shl('crc', -shift_val)).simplify()
1468 else:
1469 crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
1470 else:
1471 shift_val = opt.width - opt.tbl_idx_width
1472 crc_shifted_right = expr.Parenthesis(expr.Shr('crc', shift_val)).simplify()
1473
1474 if opt.width is not None and opt.tbl_idx_width is not None and opt.width <= opt.tbl_idx_width:
1475 crc_xor_expr = '0'
1476 else:
1477 crc_xor_expr = '(crc << {cfg_table_idx_width})'.format(**sym)
1478
1479 if opt.tbl_idx_width == 8:
1480 if opt.slice_by > 1:
1481 crc_lookup = 'crc_table[0][tbl_idx]'
1482 else:
1483 crc_lookup = 'crc_table[tbl_idx]'
1484 out += [
1485 Conditional2(opt, '', opt.width is None or opt.width > 8, [
1486 'tbl_idx = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_shifted_right, '*d')), sym['crc_table_mask']).simplify())
1487 ], [
1488 'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, '*d').simplify())
1489 ]),
1490 'crc = {0};'.format(expr.And(expr.Parenthesis(expr.Xor(crc_lookup, crc_xor_expr)), sym['cfg_mask']).simplify())
1491 ]
1492 else:
1493 crc_lookup = 'crc_table[tbl_idx & {crc_table_mask}]'.format(**sym)
1494 for i in range(8 // opt.tbl_idx_width):
1495 str_idx = '{0:d}'.format(8 - (i + 1) * opt.tbl_idx_width)
1496 out += [
1497 'tbl_idx = {0};'.format(expr.Xor(crc_shifted_right, expr.Parenthesis(expr.Shr('*d', str_idx)))),
1498 'crc = {0};'.format(expr.Xor(crc_lookup, crc_xor_expr).simplify()),
1499 ]
1500 return CodeGen(opt, '', out)
1501
1502def _crc_table_slice_by_algorithm(opt, sym):
1503 update_be = []
1504 for i in range(opt.slice_by // 4):
1505 vard = 'd{0}'.format(opt.slice_by // 4 - i)
1506 for j in range(4):
1507 idx1 = i * 4 + j
1508 idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, j*8)), expr.Terminal(255, '0xffu')).simplify()
1509 update_be.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
1510
1511 update_le = []
1512 for i in range(opt.slice_by // 4):
1513 vard = 'd{0}'.format(opt.slice_by // 4 - i)
1514 for j in range(4):
1515 idx1 = i * 4 + j
1516 idx2 = expr.And(expr.Parenthesis(expr.Shr(vard, 24 - j*8)), expr.Terminal(255, '0xffu')).simplify()
1517 update_le.append('crc_table[{0}][{1}]{2}'.format(idx1, idx2, ' ^' if idx1 < opt.slice_by - 1 else ';'))
1518
1519 out = [
1520 'const uint32_t *d32 = (const uint32_t *)d;',
1521 'while (data_len >= {crc_slice_by})'.format(**sym),
1522 '{',
1523 CodeGen(opt, 4*' ', [
1524 CodeGen(opt, None, [
1525 '#if __BYTE_ORDER == __BIG_ENDIAN',
1526 ]),
1527 '{crc_t} d1 = *d32++ ^ le16toh(crc);'.format(**sym),
1528 Conditional(opt, '', opt.slice_by >= 8, [
1529 '{crc_t} d2 = *d32++;'.format(**sym),
1530 ]),
1531 Conditional(opt, '', opt.slice_by >= 16, [
1532 '{crc_t} d3 = *d32++;'.format(**sym),
1533 '{crc_t} d4 = *d32++;'.format(**sym),
1534 ]),
1535 'crc =',
1536 CodeGen(opt, 4*' ', update_be),
1537 CodeGen(opt, None, [
1538 '#else',
1539 ]),
1540 '{crc_t} d1 = *d32++ ^ crc;'.format(**sym),
1541 Conditional(opt, '', opt.slice_by >= 8, [
1542 '{crc_t} d2 = *d32++;'.format(**sym),
1543 ]),
1544 Conditional(opt, '', opt.slice_by >= 16, [
1545 '{crc_t} d3 = *d32++;'.format(**sym),
1546 '{crc_t} d4 = *d32++;'.format(**sym),
1547 ]),
1548 'crc =',
1549 CodeGen(opt, 4*' ', update_le),
1550 CodeGen(opt, None, [
1551 '#endif',
1552 ]),
1553 '',
1554 'data_len -= {crc_slice_by};'.format(**sym),
1555 ]),
1556 '}',
1557 '',
1558 ]
1559 return CodeGen(opt, '', out)