131c89102SEric Biggers#!/usr/bin/env python3 231c89102SEric Biggers# SPDX-License-Identifier: GPL-2.0-or-later 331c89102SEric Biggers# 431c89102SEric Biggers# Script that generates constants for computing the given CRC variant(s). 531c89102SEric Biggers# 631c89102SEric Biggers# Copyright 2025 Google LLC 731c89102SEric Biggers# 831c89102SEric Biggers# Author: Eric Biggers <ebiggers@google.com> 931c89102SEric Biggers 1031c89102SEric Biggersimport sys 1131c89102SEric Biggers 1231c89102SEric Biggers# XOR (add) an iterable of polynomials. 1331c89102SEric Biggersdef xor(iterable): 1431c89102SEric Biggers res = 0 1531c89102SEric Biggers for val in iterable: 1631c89102SEric Biggers res ^= val 1731c89102SEric Biggers return res 1831c89102SEric Biggers 1931c89102SEric Biggers# Multiply two polynomials. 2031c89102SEric Biggersdef clmul(a, b): 2131c89102SEric Biggers return xor(a << i for i in range(b.bit_length()) if (b & (1 << i)) != 0) 2231c89102SEric Biggers 2331c89102SEric Biggers# Polynomial division floor(a / b). 2431c89102SEric Biggersdef div(a, b): 2531c89102SEric Biggers q = 0 2631c89102SEric Biggers while a.bit_length() >= b.bit_length(): 2731c89102SEric Biggers q ^= 1 << (a.bit_length() - b.bit_length()) 2831c89102SEric Biggers a ^= b << (a.bit_length() - b.bit_length()) 2931c89102SEric Biggers return q 3031c89102SEric Biggers 3131c89102SEric Biggers# Reduce the polynomial 'a' modulo the polynomial 'b'. 3231c89102SEric Biggersdef reduce(a, b): 3331c89102SEric Biggers return a ^ clmul(div(a, b), b) 3431c89102SEric Biggers 3531c89102SEric Biggers# Reflect the bits of a polynomial. 3631c89102SEric Biggersdef bitreflect(poly, num_bits): 3731c89102SEric Biggers assert poly.bit_length() <= num_bits 3831c89102SEric Biggers return xor(((poly >> i) & 1) << (num_bits - 1 - i) for i in range(num_bits)) 3931c89102SEric Biggers 4031c89102SEric Biggers# Format a polynomial as hex. Bit-reflect it if the CRC is lsb-first. 4131c89102SEric Biggersdef fmt_poly(variant, poly, num_bits): 4231c89102SEric Biggers if variant.lsb: 4331c89102SEric Biggers poly = bitreflect(poly, num_bits) 4431c89102SEric Biggers return f'0x{poly:0{2*num_bits//8}x}' 4531c89102SEric Biggers 4631c89102SEric Biggers# Print a pair of 64-bit polynomial multipliers. They are always passed in the 4731c89102SEric Biggers# order [HI64_TERMS, LO64_TERMS] but will be printed in the appropriate order. 4831c89102SEric Biggersdef print_mult_pair(variant, mults): 4931c89102SEric Biggers mults = list(mults if variant.lsb else reversed(mults)) 5031c89102SEric Biggers terms = ['HI64_TERMS', 'LO64_TERMS'] if variant.lsb else ['LO64_TERMS', 'HI64_TERMS'] 5131c89102SEric Biggers for i in range(2): 5231c89102SEric Biggers print(f'\t\t{fmt_poly(variant, mults[i]["val"], 64)},\t/* {terms[i]}: {mults[i]["desc"]} */') 5331c89102SEric Biggers 5431c89102SEric Biggers# Pretty-print a polynomial. 5531c89102SEric Biggersdef pprint_poly(prefix, poly): 5631c89102SEric Biggers terms = [f'x^{i}' for i in reversed(range(poly.bit_length())) 5731c89102SEric Biggers if (poly & (1 << i)) != 0] 5831c89102SEric Biggers j = 0 5931c89102SEric Biggers while j < len(terms): 6031c89102SEric Biggers s = prefix + terms[j] + (' +' if j < len(terms) - 1 else '') 6131c89102SEric Biggers j += 1 6231c89102SEric Biggers while j < len(terms) and len(s) < 73: 6331c89102SEric Biggers s += ' ' + terms[j] + (' +' if j < len(terms) - 1 else '') 6431c89102SEric Biggers j += 1 6531c89102SEric Biggers print(s) 6631c89102SEric Biggers prefix = ' * ' + (' ' * (len(prefix) - 3)) 6731c89102SEric Biggers 6831c89102SEric Biggers# Print a comment describing constants generated for the given CRC variant. 6931c89102SEric Biggersdef print_header(variant, what): 7031c89102SEric Biggers print('/*') 7131c89102SEric Biggers s = f'{"least" if variant.lsb else "most"}-significant-bit-first CRC-{variant.bits}' 7231c89102SEric Biggers print(f' * {what} generated for {s} using') 7331c89102SEric Biggers pprint_poly(' * G(x) = ', variant.G) 7431c89102SEric Biggers print(' */') 7531c89102SEric Biggers 7631c89102SEric Biggersclass CrcVariant: 7731c89102SEric Biggers def __init__(self, bits, generator_poly, bit_order): 7831c89102SEric Biggers self.bits = bits 7931c89102SEric Biggers if bit_order not in ['lsb', 'msb']: 8031c89102SEric Biggers raise ValueError('Invalid value for bit_order') 8131c89102SEric Biggers self.lsb = bit_order == 'lsb' 8231c89102SEric Biggers self.name = f'crc{bits}_{bit_order}_0x{generator_poly:0{(2*bits+7)//8}x}' 8331c89102SEric Biggers if self.lsb: 8431c89102SEric Biggers generator_poly = bitreflect(generator_poly, bits) 8531c89102SEric Biggers self.G = generator_poly ^ (1 << bits) 8631c89102SEric Biggers 8731c89102SEric Biggers# Generate tables for CRC computation using the "slice-by-N" method. 8831c89102SEric Biggers# N=1 corresponds to the traditional byte-at-a-time table. 8931c89102SEric Biggersdef gen_slicebyN_tables(variants, n): 9031c89102SEric Biggers for v in variants: 9131c89102SEric Biggers print('') 9231c89102SEric Biggers print_header(v, f'Slice-by-{n} CRC table') 9331c89102SEric Biggers print(f'static const u{v.bits} __maybe_unused {v.name}_table[{256*n}] = {{') 9431c89102SEric Biggers s = '' 9531c89102SEric Biggers for i in range(256 * n): 9631c89102SEric Biggers # The i'th table entry is the CRC of the message consisting of byte 9731c89102SEric Biggers # i % 256 followed by i // 256 zero bytes. 9831c89102SEric Biggers poly = (bitreflect(i % 256, 8) if v.lsb else i % 256) << (v.bits + 8*(i//256)) 9931c89102SEric Biggers next_entry = fmt_poly(v, reduce(poly, v.G), v.bits) + ',' 10031c89102SEric Biggers if len(s + next_entry) > 71: 10131c89102SEric Biggers print(f'\t{s}') 10231c89102SEric Biggers s = '' 10331c89102SEric Biggers s += (' ' if s else '') + next_entry 10431c89102SEric Biggers if s: 10531c89102SEric Biggers print(f'\t{s}') 10631c89102SEric Biggers print('};') 10731c89102SEric Biggers 108*bbe2610bSEric Biggersdef print_riscv_const(v, bits_per_long, name, val, desc): 109*bbe2610bSEric Biggers print(f'\t.{name} = {fmt_poly(v, val, bits_per_long)}, /* {desc} */') 110*bbe2610bSEric Biggers 111*bbe2610bSEric Biggersdef do_gen_riscv_clmul_consts(v, bits_per_long): 112*bbe2610bSEric Biggers (G, n, lsb) = (v.G, v.bits, v.lsb) 113*bbe2610bSEric Biggers 114*bbe2610bSEric Biggers pow_of_x = 3 * bits_per_long - (1 if lsb else 0) 115*bbe2610bSEric Biggers print_riscv_const(v, bits_per_long, 'fold_across_2_longs_const_hi', 116*bbe2610bSEric Biggers reduce(1 << pow_of_x, G), f'x^{pow_of_x} mod G') 117*bbe2610bSEric Biggers pow_of_x = 2 * bits_per_long - (1 if lsb else 0) 118*bbe2610bSEric Biggers print_riscv_const(v, bits_per_long, 'fold_across_2_longs_const_lo', 119*bbe2610bSEric Biggers reduce(1 << pow_of_x, G), f'x^{pow_of_x} mod G') 120*bbe2610bSEric Biggers 121*bbe2610bSEric Biggers pow_of_x = bits_per_long - 1 + n 122*bbe2610bSEric Biggers print_riscv_const(v, bits_per_long, 'barrett_reduction_const_1', 123*bbe2610bSEric Biggers div(1 << pow_of_x, G), f'floor(x^{pow_of_x} / G)') 124*bbe2610bSEric Biggers 125*bbe2610bSEric Biggers val = G - (1 << n) 126*bbe2610bSEric Biggers desc = f'G - x^{n}' 127*bbe2610bSEric Biggers if lsb: 128*bbe2610bSEric Biggers val <<= bits_per_long - n 129*bbe2610bSEric Biggers desc = f'({desc}) * x^{bits_per_long - n}' 130*bbe2610bSEric Biggers print_riscv_const(v, bits_per_long, 'barrett_reduction_const_2', val, desc) 131*bbe2610bSEric Biggers 132*bbe2610bSEric Biggersdef gen_riscv_clmul_consts(variants): 133*bbe2610bSEric Biggers print('') 134*bbe2610bSEric Biggers print('struct crc_clmul_consts {'); 135*bbe2610bSEric Biggers print('\tunsigned long fold_across_2_longs_const_hi;'); 136*bbe2610bSEric Biggers print('\tunsigned long fold_across_2_longs_const_lo;'); 137*bbe2610bSEric Biggers print('\tunsigned long barrett_reduction_const_1;'); 138*bbe2610bSEric Biggers print('\tunsigned long barrett_reduction_const_2;'); 139*bbe2610bSEric Biggers print('};'); 140*bbe2610bSEric Biggers for v in variants: 141*bbe2610bSEric Biggers print(''); 142*bbe2610bSEric Biggers if v.bits > 32: 143*bbe2610bSEric Biggers print_header(v, 'Constants') 144*bbe2610bSEric Biggers print('#ifdef CONFIG_64BIT') 145*bbe2610bSEric Biggers print(f'static const struct crc_clmul_consts {v.name}_consts __maybe_unused = {{') 146*bbe2610bSEric Biggers do_gen_riscv_clmul_consts(v, 64) 147*bbe2610bSEric Biggers print('};') 148*bbe2610bSEric Biggers print('#endif') 149*bbe2610bSEric Biggers else: 150*bbe2610bSEric Biggers print_header(v, 'Constants') 151*bbe2610bSEric Biggers print(f'static const struct crc_clmul_consts {v.name}_consts __maybe_unused = {{') 152*bbe2610bSEric Biggers print('#ifdef CONFIG_64BIT') 153*bbe2610bSEric Biggers do_gen_riscv_clmul_consts(v, 64) 154*bbe2610bSEric Biggers print('#else') 155*bbe2610bSEric Biggers do_gen_riscv_clmul_consts(v, 32) 156*bbe2610bSEric Biggers print('#endif') 157*bbe2610bSEric Biggers print('};') 158*bbe2610bSEric Biggers 15931c89102SEric Biggers# Generate constants for carryless multiplication based CRC computation. 16031c89102SEric Biggersdef gen_x86_pclmul_consts(variants): 16131c89102SEric Biggers # These are the distances, in bits, to generate folding constants for. 16231c89102SEric Biggers FOLD_DISTANCES = [2048, 1024, 512, 256, 128] 16331c89102SEric Biggers 16431c89102SEric Biggers for v in variants: 16531c89102SEric Biggers (G, n, lsb) = (v.G, v.bits, v.lsb) 16631c89102SEric Biggers print('') 16731c89102SEric Biggers print_header(v, 'CRC folding constants') 16831c89102SEric Biggers print('static const struct {') 16931c89102SEric Biggers if not lsb: 17031c89102SEric Biggers print('\tu8 bswap_mask[16];') 17131c89102SEric Biggers for i in FOLD_DISTANCES: 17231c89102SEric Biggers print(f'\tu64 fold_across_{i}_bits_consts[2];') 17331c89102SEric Biggers print('\tu8 shuf_table[48];') 17431c89102SEric Biggers print('\tu64 barrett_reduction_consts[2];') 17531c89102SEric Biggers print(f'}} {v.name}_consts ____cacheline_aligned __maybe_unused = {{') 17631c89102SEric Biggers 17731c89102SEric Biggers # Byte-reflection mask, needed for msb-first CRCs 17831c89102SEric Biggers if not lsb: 17931c89102SEric Biggers print('\t.bswap_mask = {' + ', '.join(str(i) for i in reversed(range(16))) + '},') 18031c89102SEric Biggers 18131c89102SEric Biggers # Fold constants for all distances down to 128 bits 18231c89102SEric Biggers for i in FOLD_DISTANCES: 18331c89102SEric Biggers print(f'\t.fold_across_{i}_bits_consts = {{') 18431c89102SEric Biggers # Given 64x64 => 128 bit carryless multiplication instructions, two 18531c89102SEric Biggers # 64-bit fold constants are needed per "fold distance" i: one for 18631c89102SEric Biggers # HI64_TERMS that is basically x^(i+64) mod G and one for LO64_TERMS 18731c89102SEric Biggers # that is basically x^i mod G. The exact values however undergo a 18831c89102SEric Biggers # couple adjustments, described below. 18931c89102SEric Biggers mults = [] 19031c89102SEric Biggers for j in [64, 0]: 19131c89102SEric Biggers pow_of_x = i + j 19231c89102SEric Biggers if lsb: 19331c89102SEric Biggers # Each 64x64 => 128 bit carryless multiplication instruction 19431c89102SEric Biggers # actually generates a 127-bit product in physical bits 0 19531c89102SEric Biggers # through 126, which in the lsb-first case represent the 19631c89102SEric Biggers # coefficients of x^1 through x^127, not x^0 through x^126. 19731c89102SEric Biggers # Thus in the lsb-first case, each such instruction 19831c89102SEric Biggers # implicitly adds an extra factor of x. The below removes a 19931c89102SEric Biggers # factor of x from each constant to compensate for this. 20031c89102SEric Biggers # For n < 64 the x could be removed from either the reduced 20131c89102SEric Biggers # part or unreduced part, but for n == 64 the reduced part 20231c89102SEric Biggers # is the only option. Just always use the reduced part. 20331c89102SEric Biggers pow_of_x -= 1 20431c89102SEric Biggers # Make a factor of x^(64-n) be applied unreduced rather than 20531c89102SEric Biggers # reduced, to cause the product to use only the x^(64-n) and 20631c89102SEric Biggers # higher terms and always be zero in the lower terms. Usually 20731c89102SEric Biggers # this makes no difference as it does not affect the product's 20831c89102SEric Biggers # congruence class mod G and the constant remains 64-bit, but 20931c89102SEric Biggers # part of the final reduction from 128 bits does rely on this 21031c89102SEric Biggers # property when it reuses one of the constants. 21131c89102SEric Biggers pow_of_x -= 64 - n 21231c89102SEric Biggers mults.append({ 'val': reduce(1 << pow_of_x, G) << (64 - n), 21331c89102SEric Biggers 'desc': f'(x^{pow_of_x} mod G) * x^{64-n}' }) 21431c89102SEric Biggers print_mult_pair(v, mults) 21531c89102SEric Biggers print('\t},') 21631c89102SEric Biggers 21731c89102SEric Biggers # Shuffle table for handling 1..15 bytes at end 21831c89102SEric Biggers print('\t.shuf_table = {') 21931c89102SEric Biggers print('\t\t' + (16*'-1, ').rstrip()) 22031c89102SEric Biggers print('\t\t' + ''.join(f'{i:2}, ' for i in range(16)).rstrip()) 22131c89102SEric Biggers print('\t\t' + (16*'-1, ').rstrip()) 22231c89102SEric Biggers print('\t},') 22331c89102SEric Biggers 22431c89102SEric Biggers # Barrett reduction constants for reducing 128 bits to the final CRC 22531c89102SEric Biggers print('\t.barrett_reduction_consts = {') 22631c89102SEric Biggers mults = [] 22731c89102SEric Biggers 22831c89102SEric Biggers val = div(1 << (63+n), G) 22931c89102SEric Biggers desc = f'floor(x^{63+n} / G)' 23031c89102SEric Biggers if not lsb: 23131c89102SEric Biggers val = (val << 1) - (1 << 64) 23231c89102SEric Biggers desc = f'({desc} * x) - x^64' 23331c89102SEric Biggers mults.append({ 'val': val, 'desc': desc }) 23431c89102SEric Biggers 23531c89102SEric Biggers val = G - (1 << n) 23631c89102SEric Biggers desc = f'G - x^{n}' 23731c89102SEric Biggers if lsb and n == 64: 23831c89102SEric Biggers assert (val & 1) != 0 # The x^0 term should always be nonzero. 23931c89102SEric Biggers val >>= 1 24031c89102SEric Biggers desc = f'({desc} - x^0) / x' 24131c89102SEric Biggers else: 24231c89102SEric Biggers pow_of_x = 64 - n - (1 if lsb else 0) 24331c89102SEric Biggers val <<= pow_of_x 24431c89102SEric Biggers desc = f'({desc}) * x^{pow_of_x}' 24531c89102SEric Biggers mults.append({ 'val': val, 'desc': desc }) 24631c89102SEric Biggers 24731c89102SEric Biggers print_mult_pair(v, mults) 24831c89102SEric Biggers print('\t},') 24931c89102SEric Biggers 25031c89102SEric Biggers print('};') 25131c89102SEric Biggers 25231c89102SEric Biggersdef parse_crc_variants(vars_string): 25331c89102SEric Biggers variants = [] 25431c89102SEric Biggers for var_string in vars_string.split(','): 25531c89102SEric Biggers bits, bit_order, generator_poly = var_string.split('_') 25631c89102SEric Biggers assert bits.startswith('crc') 25731c89102SEric Biggers bits = int(bits.removeprefix('crc')) 25831c89102SEric Biggers assert generator_poly.startswith('0x') 25931c89102SEric Biggers generator_poly = generator_poly.removeprefix('0x') 26031c89102SEric Biggers assert len(generator_poly) % 2 == 0 26131c89102SEric Biggers generator_poly = int(generator_poly, 16) 26231c89102SEric Biggers variants.append(CrcVariant(bits, generator_poly, bit_order)) 26331c89102SEric Biggers return variants 26431c89102SEric Biggers 26531c89102SEric Biggersif len(sys.argv) != 3: 26631c89102SEric Biggers sys.stderr.write(f'Usage: {sys.argv[0]} CONSTS_TYPE[,CONSTS_TYPE]... CRC_VARIANT[,CRC_VARIANT]...\n') 267*bbe2610bSEric Biggers sys.stderr.write(' CONSTS_TYPE can be sliceby[1-8], riscv_clmul, or x86_pclmul\n') 26831c89102SEric Biggers sys.stderr.write(' CRC_VARIANT is crc${num_bits}_${bit_order}_${generator_poly_as_hex}\n') 26931c89102SEric Biggers sys.stderr.write(' E.g. crc16_msb_0x8bb7 or crc32_lsb_0xedb88320\n') 27031c89102SEric Biggers sys.stderr.write(' Polynomial must use the given bit_order and exclude x^{num_bits}\n') 27131c89102SEric Biggers sys.exit(1) 27231c89102SEric Biggers 27331c89102SEric Biggersprint('/* SPDX-License-Identifier: GPL-2.0-or-later */') 27431c89102SEric Biggersprint('/*') 27531c89102SEric Biggersprint(' * CRC constants generated by:') 27631c89102SEric Biggersprint(' *') 27731c89102SEric Biggersprint(f' *\t{sys.argv[0]} {" ".join(sys.argv[1:])}') 27831c89102SEric Biggersprint(' *') 27931c89102SEric Biggersprint(' * Do not edit manually.') 28031c89102SEric Biggersprint(' */') 28131c89102SEric Biggersconsts_types = sys.argv[1].split(',') 28231c89102SEric Biggersvariants = parse_crc_variants(sys.argv[2]) 28331c89102SEric Biggersfor consts_type in consts_types: 28431c89102SEric Biggers if consts_type.startswith('sliceby'): 28531c89102SEric Biggers gen_slicebyN_tables(variants, int(consts_type.removeprefix('sliceby'))) 286*bbe2610bSEric Biggers elif consts_type == 'riscv_clmul': 287*bbe2610bSEric Biggers gen_riscv_clmul_consts(variants) 28831c89102SEric Biggers elif consts_type == 'x86_pclmul': 28931c89102SEric Biggers gen_x86_pclmul_consts(variants) 29031c89102SEric Biggers else: 29131c89102SEric Biggers raise ValueError(f'Unknown consts_type: {consts_type}') 292