xref: /linux/scripts/gen-crc-consts.py (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
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