gen-crc-consts.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #!/usr/bin/env python3
  2. # SPDX-License-Identifier: GPL-2.0-or-later
  3. #
  4. # Script that generates constants for computing the given CRC variant(s).
  5. #
  6. # Copyright 2025 Google LLC
  7. #
  8. # Author: Eric Biggers <ebiggers@google.com>
  9. import sys
  10. # XOR (add) an iterable of polynomials.
  11. def xor(iterable):
  12. res = 0
  13. for val in iterable:
  14. res ^= val
  15. return res
  16. # Multiply two polynomials.
  17. def clmul(a, b):
  18. return xor(a << i for i in range(b.bit_length()) if (b & (1 << i)) != 0)
  19. # Polynomial division floor(a / b).
  20. def div(a, b):
  21. q = 0
  22. while a.bit_length() >= b.bit_length():
  23. q ^= 1 << (a.bit_length() - b.bit_length())
  24. a ^= b << (a.bit_length() - b.bit_length())
  25. return q
  26. # Reduce the polynomial 'a' modulo the polynomial 'b'.
  27. def reduce(a, b):
  28. return a ^ clmul(div(a, b), b)
  29. # Reflect the bits of a polynomial.
  30. def bitreflect(poly, num_bits):
  31. assert poly.bit_length() <= num_bits
  32. return xor(((poly >> i) & 1) << (num_bits - 1 - i) for i in range(num_bits))
  33. # Format a polynomial as hex. Bit-reflect it if the CRC is lsb-first.
  34. def fmt_poly(variant, poly, num_bits):
  35. if variant.lsb:
  36. poly = bitreflect(poly, num_bits)
  37. return f'0x{poly:0{2*num_bits//8}x}'
  38. # Print a pair of 64-bit polynomial multipliers. They are always passed in the
  39. # order [HI64_TERMS, LO64_TERMS] but will be printed in the appropriate order.
  40. def print_mult_pair(variant, mults):
  41. mults = list(mults if variant.lsb else reversed(mults))
  42. terms = ['HI64_TERMS', 'LO64_TERMS'] if variant.lsb else ['LO64_TERMS', 'HI64_TERMS']
  43. for i in range(2):
  44. print(f'\t\t{fmt_poly(variant, mults[i]["val"], 64)},\t/* {terms[i]}: {mults[i]["desc"]} */')
  45. # Pretty-print a polynomial.
  46. def pprint_poly(prefix, poly):
  47. terms = [f'x^{i}' for i in reversed(range(poly.bit_length()))
  48. if (poly & (1 << i)) != 0]
  49. j = 0
  50. while j < len(terms):
  51. s = prefix + terms[j] + (' +' if j < len(terms) - 1 else '')
  52. j += 1
  53. while j < len(terms) and len(s) < 73:
  54. s += ' ' + terms[j] + (' +' if j < len(terms) - 1 else '')
  55. j += 1
  56. print(s)
  57. prefix = ' * ' + (' ' * (len(prefix) - 3))
  58. # Print a comment describing constants generated for the given CRC variant.
  59. def print_header(variant, what):
  60. print('/*')
  61. s = f'{"least" if variant.lsb else "most"}-significant-bit-first CRC-{variant.bits}'
  62. print(f' * {what} generated for {s} using')
  63. pprint_poly(' * G(x) = ', variant.G)
  64. print(' */')
  65. class CrcVariant:
  66. def __init__(self, bits, generator_poly, bit_order):
  67. self.bits = bits
  68. if bit_order not in ['lsb', 'msb']:
  69. raise ValueError('Invalid value for bit_order')
  70. self.lsb = bit_order == 'lsb'
  71. self.name = f'crc{bits}_{bit_order}_0x{generator_poly:0{(2*bits+7)//8}x}'
  72. if self.lsb:
  73. generator_poly = bitreflect(generator_poly, bits)
  74. self.G = generator_poly ^ (1 << bits)
  75. # Generate tables for CRC computation using the "slice-by-N" method.
  76. # N=1 corresponds to the traditional byte-at-a-time table.
  77. def gen_slicebyN_tables(variants, n):
  78. for v in variants:
  79. print('')
  80. print_header(v, f'Slice-by-{n} CRC table')
  81. print(f'static const u{v.bits} __maybe_unused {v.name}_table[{256*n}] = {{')
  82. s = ''
  83. for i in range(256 * n):
  84. # The i'th table entry is the CRC of the message consisting of byte
  85. # i % 256 followed by i // 256 zero bytes.
  86. poly = (bitreflect(i % 256, 8) if v.lsb else i % 256) << (v.bits + 8*(i//256))
  87. next_entry = fmt_poly(v, reduce(poly, v.G), v.bits) + ','
  88. if len(s + next_entry) > 71:
  89. print(f'\t{s}')
  90. s = ''
  91. s += (' ' if s else '') + next_entry
  92. if s:
  93. print(f'\t{s}')
  94. print('};')
  95. def print_riscv_const(v, bits_per_long, name, val, desc):
  96. print(f'\t.{name} = {fmt_poly(v, val, bits_per_long)}, /* {desc} */')
  97. def do_gen_riscv_clmul_consts(v, bits_per_long):
  98. (G, n, lsb) = (v.G, v.bits, v.lsb)
  99. pow_of_x = 3 * bits_per_long - (1 if lsb else 0)
  100. print_riscv_const(v, bits_per_long, 'fold_across_2_longs_const_hi',
  101. reduce(1 << pow_of_x, G), f'x^{pow_of_x} mod G')
  102. pow_of_x = 2 * bits_per_long - (1 if lsb else 0)
  103. print_riscv_const(v, bits_per_long, 'fold_across_2_longs_const_lo',
  104. reduce(1 << pow_of_x, G), f'x^{pow_of_x} mod G')
  105. pow_of_x = bits_per_long - 1 + n
  106. print_riscv_const(v, bits_per_long, 'barrett_reduction_const_1',
  107. div(1 << pow_of_x, G), f'floor(x^{pow_of_x} / G)')
  108. val = G - (1 << n)
  109. desc = f'G - x^{n}'
  110. if lsb:
  111. val <<= bits_per_long - n
  112. desc = f'({desc}) * x^{bits_per_long - n}'
  113. print_riscv_const(v, bits_per_long, 'barrett_reduction_const_2', val, desc)
  114. def gen_riscv_clmul_consts(variants):
  115. print('')
  116. print('struct crc_clmul_consts {');
  117. print('\tunsigned long fold_across_2_longs_const_hi;');
  118. print('\tunsigned long fold_across_2_longs_const_lo;');
  119. print('\tunsigned long barrett_reduction_const_1;');
  120. print('\tunsigned long barrett_reduction_const_2;');
  121. print('};');
  122. for v in variants:
  123. print('');
  124. if v.bits > 32:
  125. print_header(v, 'Constants')
  126. print('#ifdef CONFIG_64BIT')
  127. print(f'static const struct crc_clmul_consts {v.name}_consts __maybe_unused = {{')
  128. do_gen_riscv_clmul_consts(v, 64)
  129. print('};')
  130. print('#endif')
  131. else:
  132. print_header(v, 'Constants')
  133. print(f'static const struct crc_clmul_consts {v.name}_consts __maybe_unused = {{')
  134. print('#ifdef CONFIG_64BIT')
  135. do_gen_riscv_clmul_consts(v, 64)
  136. print('#else')
  137. do_gen_riscv_clmul_consts(v, 32)
  138. print('#endif')
  139. print('};')
  140. # Generate constants for carryless multiplication based CRC computation.
  141. def gen_x86_pclmul_consts(variants):
  142. # These are the distances, in bits, to generate folding constants for.
  143. FOLD_DISTANCES = [2048, 1024, 512, 256, 128]
  144. for v in variants:
  145. (G, n, lsb) = (v.G, v.bits, v.lsb)
  146. print('')
  147. print_header(v, 'CRC folding constants')
  148. print('static const struct {')
  149. if not lsb:
  150. print('\tu8 bswap_mask[16];')
  151. for i in FOLD_DISTANCES:
  152. print(f'\tu64 fold_across_{i}_bits_consts[2];')
  153. print('\tu8 shuf_table[48];')
  154. print('\tu64 barrett_reduction_consts[2];')
  155. print(f'}} {v.name}_consts ____cacheline_aligned __maybe_unused = {{')
  156. # Byte-reflection mask, needed for msb-first CRCs
  157. if not lsb:
  158. print('\t.bswap_mask = {' + ', '.join(str(i) for i in reversed(range(16))) + '},')
  159. # Fold constants for all distances down to 128 bits
  160. for i in FOLD_DISTANCES:
  161. print(f'\t.fold_across_{i}_bits_consts = {{')
  162. # Given 64x64 => 128 bit carryless multiplication instructions, two
  163. # 64-bit fold constants are needed per "fold distance" i: one for
  164. # HI64_TERMS that is basically x^(i+64) mod G and one for LO64_TERMS
  165. # that is basically x^i mod G. The exact values however undergo a
  166. # couple adjustments, described below.
  167. mults = []
  168. for j in [64, 0]:
  169. pow_of_x = i + j
  170. if lsb:
  171. # Each 64x64 => 128 bit carryless multiplication instruction
  172. # actually generates a 127-bit product in physical bits 0
  173. # through 126, which in the lsb-first case represent the
  174. # coefficients of x^1 through x^127, not x^0 through x^126.
  175. # Thus in the lsb-first case, each such instruction
  176. # implicitly adds an extra factor of x. The below removes a
  177. # factor of x from each constant to compensate for this.
  178. # For n < 64 the x could be removed from either the reduced
  179. # part or unreduced part, but for n == 64 the reduced part
  180. # is the only option. Just always use the reduced part.
  181. pow_of_x -= 1
  182. # Make a factor of x^(64-n) be applied unreduced rather than
  183. # reduced, to cause the product to use only the x^(64-n) and
  184. # higher terms and always be zero in the lower terms. Usually
  185. # this makes no difference as it does not affect the product's
  186. # congruence class mod G and the constant remains 64-bit, but
  187. # part of the final reduction from 128 bits does rely on this
  188. # property when it reuses one of the constants.
  189. pow_of_x -= 64 - n
  190. mults.append({ 'val': reduce(1 << pow_of_x, G) << (64 - n),
  191. 'desc': f'(x^{pow_of_x} mod G) * x^{64-n}' })
  192. print_mult_pair(v, mults)
  193. print('\t},')
  194. # Shuffle table for handling 1..15 bytes at end
  195. print('\t.shuf_table = {')
  196. print('\t\t' + (16*'-1, ').rstrip())
  197. print('\t\t' + ''.join(f'{i:2}, ' for i in range(16)).rstrip())
  198. print('\t\t' + (16*'-1, ').rstrip())
  199. print('\t},')
  200. # Barrett reduction constants for reducing 128 bits to the final CRC
  201. print('\t.barrett_reduction_consts = {')
  202. mults = []
  203. val = div(1 << (63+n), G)
  204. desc = f'floor(x^{63+n} / G)'
  205. if not lsb:
  206. val = (val << 1) - (1 << 64)
  207. desc = f'({desc} * x) - x^64'
  208. mults.append({ 'val': val, 'desc': desc })
  209. val = G - (1 << n)
  210. desc = f'G - x^{n}'
  211. if lsb and n == 64:
  212. assert (val & 1) != 0 # The x^0 term should always be nonzero.
  213. val >>= 1
  214. desc = f'({desc} - x^0) / x'
  215. else:
  216. pow_of_x = 64 - n - (1 if lsb else 0)
  217. val <<= pow_of_x
  218. desc = f'({desc}) * x^{pow_of_x}'
  219. mults.append({ 'val': val, 'desc': desc })
  220. print_mult_pair(v, mults)
  221. print('\t},')
  222. print('};')
  223. def parse_crc_variants(vars_string):
  224. variants = []
  225. for var_string in vars_string.split(','):
  226. bits, bit_order, generator_poly = var_string.split('_')
  227. assert bits.startswith('crc')
  228. bits = int(bits.removeprefix('crc'))
  229. assert generator_poly.startswith('0x')
  230. generator_poly = generator_poly.removeprefix('0x')
  231. assert len(generator_poly) % 2 == 0
  232. generator_poly = int(generator_poly, 16)
  233. variants.append(CrcVariant(bits, generator_poly, bit_order))
  234. return variants
  235. if len(sys.argv) != 3:
  236. sys.stderr.write(f'Usage: {sys.argv[0]} CONSTS_TYPE[,CONSTS_TYPE]... CRC_VARIANT[,CRC_VARIANT]...\n')
  237. sys.stderr.write(' CONSTS_TYPE can be sliceby[1-8], riscv_clmul, or x86_pclmul\n')
  238. sys.stderr.write(' CRC_VARIANT is crc${num_bits}_${bit_order}_${generator_poly_as_hex}\n')
  239. sys.stderr.write(' E.g. crc16_msb_0x8bb7 or crc32_lsb_0xedb88320\n')
  240. sys.stderr.write(' Polynomial must use the given bit_order and exclude x^{num_bits}\n')
  241. sys.exit(1)
  242. print('/* SPDX-License-Identifier: GPL-2.0-or-later */')
  243. print('/*')
  244. print(' * CRC constants generated by:')
  245. print(' *')
  246. print(f' *\t{sys.argv[0]} {" ".join(sys.argv[1:])}')
  247. print(' *')
  248. print(' * Do not edit manually.')
  249. print(' */')
  250. consts_types = sys.argv[1].split(',')
  251. variants = parse_crc_variants(sys.argv[2])
  252. for consts_type in consts_types:
  253. if consts_type.startswith('sliceby'):
  254. gen_slicebyN_tables(variants, int(consts_type.removeprefix('sliceby')))
  255. elif consts_type == 'riscv_clmul':
  256. gen_riscv_clmul_consts(variants)
  257. elif consts_type == 'x86_pclmul':
  258. gen_x86_pclmul_consts(variants)
  259. else:
  260. raise ValueError(f'Unknown consts_type: {consts_type}')