Repository: amaranth-lang/amaranth
Pull request #681 (2022-01-31 18:43:49)

Add CRC generator
This PR adds a CRC generator to the stdlib. It supports the full set of Williams/Rocksoft model parameters, which in practice means it should be able to generate and validate pretty much every commonly used CRC directly, and significantly that includes all the ones in the [reveng catalogue](https://reveng.sourceforge.io/crc-catalogue/) and [crcmod predefined list](http://crcmod.sourceforge.net/crcmod.predefined.html).

It's configurable for arbitrary input word widths with a constant single-cycle latency, so can be used to generate a classic bit-at-a-time shift-register CRC, or update wider words in parallel. It doesn't support masking the input words, which might limit its use in very wide masked data paths, though I expect that could be added later in a backwards-compatible way if necessary. I haven't thought about how masking might be implemented.

The generated logic is a product/XOR equation for each bit of the new state which includes bits of the previous state and current input. As far as I'm aware this is essentially the best way to generate an arbitrary parallel CRC in hardware.

Currently it uses a `reset` and `valid` input signal, rather than e.g. relying on users to add `EnableInserter` and `ResetInserter` as appropriate. I don't know what the preferred way to deal with that is in stdlib items. Since `reset` will pretty much always be required it seems easier to have it as an input than requiring `ResetInserter`; I guess some applications may never need to change `valid` if they always have valid new data after resetting.

The test suite uses a variety of standard CRCs to provide coverage of the various input parameters, and tests each at input word widths of 1, 2, 4, 8, 16, 32, and 64 bits.

I originally wrote this code for my work, where we've used it in a variety of applications, but I have permission to release it under the BSD two-clause licence for inclusion in Amaranth.

josuah: > Currently it uses a reset and valid input signal, rather than e.g. relying on users to add EnableInserter and ResetInserter as appropriate.

This could be affected/related to https://github.com/amaranth-lang/rfcs/pull/12
whitequark: #12 is a major rework that will not be relevant in short term (if ever).
adamgreig: I've updated to rename the `reset` signal to `rst`.
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/681?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) Report
> Merging [#681](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/681?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) (b729f4d) into [main](https://app.codecov.io/gh/amaranth-lang/amaranth/commit/7d99981d571000fb427f051f1bbe9631c1a44145?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) (7d99981) will **decrease** coverage by `0.52%`.
> The diff coverage is `100.00%`.

> :exclamation: Current head b729f4d differs from pull request most recent head f567f5a. Consider uploading reports for the commit f567f5a to get more accurate results

```diff
@@            Coverage Diff             @@
##             main     #681      +/-   ##
==========================================
- Coverage   82.15%   81.64%   -0.52%     
==========================================
  Files          51       50       -1     
  Lines        6914     6553     -361     
  Branches     1680     1548     -132     
==========================================
- Hits         5680     5350     -330     
+ Misses       1035     1012      -23     
+ Partials      199      191       -8     
```


| [Impacted Files](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/681?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang) | Coverage Δ | |
|---|---|---|
| [amaranth/lib/crc.py](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/681?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang#diff-YW1hcmFudGgvbGliL2NyYy5weQ==) | `100.00% <100.00%> (ø)` | |

... and [17 files with indirect coverage changes](https://app.codecov.io/gh/amaranth-lang/amaranth/pull/681/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=amaranth-lang)

adamgreig: This PR has been updated to address the latest review comments in https://github.com/amaranth-lang/rfcs/pull/6#issuecomment-1567391041. I've squashed the commits to a single one suitable for merging as I don't think there's any benefit to preserving the commit history.
whitequark: Do you think you could reach 100% code coverage in this PR? This is something I strive for in the core language and the standard library, although it is not currently the case everywhere.
whitequark: We also need a changelog line for the RFC and this PR -- could you add them?
whitequark: Perfect, thanks!
adamgreig: Rebased and added tests for 100% coverage of the new files.
adamgreig: Thanks for checking! I thought I had added a changelog entry [here](https://github.com/amaranth-lang/amaranth/pull/681/files#diff-13939719fa5d88ab31dfc99a49861551b8e157a0ead47125cbe28a2ab72a122d), should I do something else too?

I'll rebase now to fix the merge conflict.
whitequark: > Thanks for checking! I thought I had added a changelog entry [here](https://github.com/amaranth-lang/amaranth/pull/681/files#diff-13939719fa5d88ab31dfc99a49861551b8e157a0ead47125cbe28a2ab72a122d), should I do something else too?

Oh sorry, I completely missed that somehow!
whitequark: Could you squash the commits, please?
adamgreig: Sorry, I missed your comment last week. I've pushed a single squashed commit that's rebased on current main.

Patch:
diff --git a/amaranth/lib/crc/__init__.py b/amaranth/lib/crc/__init__.py
new file mode 100644
index 0000000..282a57a
--- /dev/null
+++ b/amaranth/lib/crc/__init__.py
@@ -0,0 +1,426 @@
+"""
+Utilities for computing cyclic redundancy checks (CRCs) in software and in
+hardware.
+
+CRCs are specified using the :py:class:`Algorithm` class, which contains
+settings for CRC width, polynomial, initial value, input/output reflection, and
+output XOR. Many commonly used CRC algorithms are available in the
+:py:mod:`~amaranth.lib.crc.catalog` module, while most other CRC designs can be
+accommodated by manually constructing :py:class:`Algorithm`.
+
+Call the :py:class:`Algorithm` with a ``data_width`` to obtain a
+:py:class:`Parameters` class, which fully defines a CRC computation. The
+:py:class:`Parameters` class provides the :py:meth:`~Parameters.compute` method
+to perform software computations, and the :py:meth:`~Parameters.create` method
+to create a hardware CRC module, :py:class:`Processor`.
+
+.. code-block::
+
+    # Create a predefined CRC16-CCITT hardware module, using the default
+    # 8-bit data width (in other words, bytes).
+    from amaranth.lib.crc.catalog import CRC16_CCITT
+    crc = m.submodules.crc = CRC16_CCITT().create()
+
+    # Create a custom CRC algorithm, specify the data width explicitly,
+    # and use it to compute a CRC value in software.
+    from amaranth.lib.crc import Algorithm
+    algo = Algorithm(crc_width=16, polynomial=0x1021, initial_crc=0xffff,
+                     reflect_input=False, reflect_output=False,
+                     xor_output=0x0000)
+    assert algo(data_width=8).compute(b"123456789") == 0x29b1
+"""
+
+from ... import *
+
+__all__ = ["Algorithm", "Parameters", "Processor", "catalog"]
+
+
+class Algorithm:
+    """
+    Settings for a CRC algorithm, excluding data width.
+
+    The parameter set is based on the Williams model from
+    "A Painless Guide to CRC Error Detection Algorithms":
+    http://www.ross.net/crc/download/crc_v3.txt
+
+    For a reference of standard CRC parameter sets, refer to:
+
+    * `reveng`_'s catalogue, which uses an identical parameterisation,
+    * `crcmod`_'s list of predefined functions, but remove the leading '1'
+      from the polynominal, XOR the "Init-value" with "XOR-out" to obtain
+      ``initial_crc``, and where "Reversed" is True, set both ``reflect_input``
+      and ``reflect_output`` to True,
+    * `CRC Zoo`_, which contains only polynomials; use the "explicit +1"
+      form of polynomial but remove the leading '1'.
+
+    .. _reveng: https://reveng.sourceforge.io/crc-catalogue/all.htm
+    .. _crcmod: http://crcmod.sourceforge.net/crcmod.predefined.html
+    .. _CRC Zoo: https://users.ece.cmu.edu/~koopman/crc/
+
+    Many commonly used CRC algorithms are available in the
+    :py:mod:`~amaranth.lib.crc.catalog` module, which includes
+    all entries in the `reveng`_ catalogue.
+
+    To create a :py:class:`Parameters` instance, call the :py:class:`Algorithm`
+    object with the required data width, which defaults to 8 bits.
+
+    Parameters
+    ----------
+    crc_width : int
+        Bit width of CRC word. Also known as "width" in the Williams model.
+    polynomial : int
+        CRC polynomial to use, ``crc_width`` bits long, without the implicit
+        ``x**crc_width`` term. Polynomial is always specified with the highest
+        order terms in the most significant bit positions; use
+        ``reflect_input`` and ``reflect_output`` to perform a least
+        significant bit first computation.
+    initial_crc : int
+        Initial value of CRC register at reset. Most significant bit always
+        corresponds to the highest order term in the CRC register.
+    reflect_input : bool
+        If True, the input data words are bit-reflected, so that they are
+        processed least significant bit first.
+    reflect_output : bool
+        If True, the output CRC is bit-reflected, so the least-significant bit
+        of the output is the highest-order bit of the CRC register.
+        Note that this reflection is performed over the entire CRC register;
+        for transmission you may want to treat the output as a little-endian
+        multi-word value, so for example the reflected 16-bit output 0x4E4C
+        would be transmitted as the two octets 0x4C 0x4E, each transmitted
+        least significant bit first.
+    xor_output : int
+        The output CRC will be the CRC register XOR'd with this value, applied
+        after any output bit-reflection.
+    """
+    def __init__(self, *, crc_width, polynomial, initial_crc, reflect_input,
+                 reflect_output, xor_output):
+        self.crc_width = int(crc_width)
+        self.polynomial = int(polynomial)
+        self.initial_crc = int(initial_crc)
+        self.reflect_input = bool(reflect_input)
+        self.reflect_output = bool(reflect_output)
+        self.xor_output = int(xor_output)
+
+        if self.crc_width <= 0:
+            raise ValueError("crc_width must be greater than 0")
+        if not 0 <= self.polynomial < 2 ** self.crc_width:
+            raise ValueError("polynomial must be between 0 and 2**crc_width - 1")
+        if not 0 <= self.initial_crc < 2 ** self.crc_width:
+            raise ValueError("initial_crc must be between 0 and 2**crc_width - 1")
+        if not 0 <= self.xor_output < 2 ** self.crc_width:
+            raise ValueError("xor_output must be between 0 and 2**crc_width - 1")
+
+    def __call__(self, data_width=8):
+        """
+        Constructs a :py:class:`Parameters` instance from this
+        :py:class:`Algorithm` with the specified ``data_width``.
+
+        Parameters
+        ----------
+        data_width : int
+            Bit width of data words, default 8.
+        """
+        return Parameters(self, data_width)
+
+    def __repr__(self):
+        return f"Algorithm(crc_width={self.crc_width}," \
+               f" polynomial=0x{self.polynomial:0{self.crc_width//4}x}," \
+               f" initial_crc=0x{self.initial_crc:0{self.crc_width//4}x}," \
+               f" reflect_input={self.reflect_input}," \
+               f" reflect_output={self.reflect_output}," \
+               f" xor_output=0x{self.xor_output:0{self.crc_width//4}x})"
+
+
+class Parameters:
+    """
+    Full set of parameters for a CRC computation.
+
+    Contains the settings from :py:class:`Algorithm` and additionally
+    ``data_width``. Refer to :py:class:`Algorithm` for details of what each
+    parameter means and how to construct them.
+
+    From this class, you can directly compute CRCs with the
+    :py:meth:`~Parameters.compute` method, or construct a hardware module with
+    the :py:meth:`~Parameters.create` method.
+
+    Parameters
+    ----------
+    algorithm : Algorithm
+        CRC algorithm to use. Specifies the CRC width, polynomial,
+        initial value, whether to reflect the input or output words,
+        and any output XOR.
+    data_width : int
+        Bit width of data words.
+    """
+    def __init__(self, algorithm, data_width=8):
+        self._crc_width = algorithm.crc_width
+        self._polynomial = algorithm.polynomial
+        self._initial_crc = algorithm.initial_crc
+        self._reflect_input = algorithm.reflect_input
+        self._reflect_output = algorithm.reflect_output
+        self._xor_output = algorithm.xor_output
+        self._data_width = int(data_width)
+        if self._data_width <= 0:
+            raise ValueError("data_width must be greater than 0")
+
+    @property
+    def algorithm(self):
+        """
+        Returns an :py:class:`Algorithm` with the CRC settings from this
+        instance.
+        """
+        return Algorithm(
+            crc_width=self._crc_width,
+            polynomial=self._polynomial,
+            initial_crc=self._initial_crc,
+            reflect_input=self._reflect_input,
+            reflect_output=self._reflect_output,
+            xor_output=self._xor_output)
+
+    def residue(self):
+        """
+        Compute the residue value for this CRC, which is the value left in the
+        CRC register after processing any valid codeword.
+        """
+        # Residue is computed by initialising to (possibly reflected)
+        # xor_output, feeding crc_width worth of 0 bits, then taking
+        # the (possibly reflected) output without any XOR.
+        if self._reflect_output:
+            init = self._reflect(self._xor_output, self._crc_width)
+        else:
+            init = self._xor_output
+        algo = self.algorithm
+        algo.initial_crc = init
+        algo.reflect_input = False
+        algo.xor_output = 0
+        return algo(data_width=self._crc_width).compute([0])
+
+    def create(self):
+        """
+        Returns a ``Processor`` configured with these parameters.
+        """
+        return Processor(self)
+
+    def compute(self, data):
+        """
+        Computes and returns the CRC of all data words in ``data``.
+
+        Parameters
+        ----------
+        data : iterable of integers
+            The CRC is computed over this complete set of data.
+            Each item is an integer of bitwidth equal to ``data_width``.
+        """
+        # Precompute some constants we use every iteration.
+        word_max = (1 << self._data_width) - 1
+        top_bit = 1 << (self._crc_width + self._data_width - 1)
+        crc_mask = (1 << (self._crc_width + self._data_width)) - 1
+        poly_shifted = self._polynomial << self._data_width
+
+        # Implementation notes:
+        # We always compute most-significant bit first, which means the
+        # polynomial and initial value may be used as-is, and the reflect_in
+        # and reflect_out values have their usual sense.
+        # However, when computing word-at-a-time and MSbit-first, we must align
+        # the input word so its MSbit lines up with the MSbit of the previous
+        # CRC value. When the CRC width is smaller than the word width, this
+        # would normally truncate data bits.
+        # Instead, we shift the initial CRC left by the data width, and the
+        # data word left by the crc width, lining up their MSbits no matter
+        # the relation between the two widths.
+        # The new CRC is then shifted right by the data width before output.
+
+        crc = self._initial_crc << self._data_width
+        for word in data:
+            if not 0 <= word <= word_max:
+                raise ValueError("data word must be between 0 and {}".format(word_max - 1))
+
+            if self._reflect_input:
+                word = self._reflect(word, self._data_width)
+
+            crc ^= word << self._crc_width
+            for _ in range(self._data_width):
+                if crc & top_bit:
+                    crc = (crc << 1) ^ poly_shifted
+                else:
+                    crc <<= 1
+            crc &= crc_mask
+
+        crc >>= self._data_width
+        if self._reflect_output:
+            crc = self._reflect(crc, self._crc_width)
+
+        crc ^= self._xor_output
+        return crc
+
+    @staticmethod
+    def _reflect(word, n):
+        """
+        Bitwise-reflects an n-bit word ``word``.
+        """
+        return int(f"{word:0{n}b}"[::-1], 2)
+
+    def _matrices(self):
+        """
+        Computes the F and G matrices for parallel CRC computation, treating
+        the CRC as a linear time-invariant system described by the state
+        relation x(t+1) = F.x(i) + G.u(i), where x(i) and u(i) are column
+        vectors of the bits of the CRC register and input word, F is the n-by-n
+        matrix relating the old state to the new state, and G is the n-by-m
+        matrix relating the new data to the new state, where n is the CRC
+        width and m is the data word width.
+
+        The matrices are ordered least-significant-bit first; in other words
+        the first entry, with index (0, 0), corresponds to the effect of the
+        least-significant bit of the input on the least-significant bit of the
+        output.
+
+        For convenience of implementation, both matrices are returned
+        transposed: the first index is the input bit, and the second index is
+        the corresponding output bit.
+
+        The matrices are used to select which bits are XORd together to compute
+        each bit i of the new state: if F[j][i] is set then bit j of the old
+        state is included in the XOR, and if G[j][i] is set then bit j of the
+        new data is included.
+
+        These matrices are not affected by ``initial_crc``, ``reflect_input``,
+        ``reflect_output``, or ``xor_output``.
+        """
+        f = []
+        g = []
+        algo = self.algorithm
+        algo.reflect_input = algo.reflect_output = False
+        algo.xor_output = 0
+        crc = Parameters(algo, self._data_width)
+        for i in range(self._crc_width):
+            crc._initial_crc = 2 ** i
+            w = crc.compute([0])
+            f.append([int(x) for x in reversed(f"{w:0{self._crc_width}b}")])
+        for i in range(self._data_width):
+            crc._initial_crc = 0
+            w = crc.compute([2 ** i])
+            g.append([int(x) for x in reversed(f"{w:0{self._crc_width}b}")])
+        return f, g
+
+    def __repr__(self):
+        return f"Parameters({self.algorithm!r}, data_width={self._data_width})"
+
+
+class Processor(Elaboratable):
+    """
+    Cyclic redundancy check (CRC) processor module.
+
+    This module generates CRCs from an input data stream, which can be used
+    to validate an existing CRC or generate a new CRC. It is configured by
+    the :py:class:`Parameters` class, which can handle most forms of CRCs.
+    Refer to that class's documentation for a description of the parameters.
+
+    The CRC value is updated on any clock cycle where ``valid`` is asserted,
+    with the updated value available on the ``crc`` output on the subsequent
+    clock cycle. The latency is therefore one clock cycle, and the throughput
+    is one data word per clock cycle.
+
+    The CRC is reset to its initial value whenever ``start`` is asserted.
+    ``start`` and ``valid`` may be asserted on the same clock cycle, in which
+    case a new CRC computation is started with the current value of ``data``.
+
+    With ``data_width=1``, a classic bit-serial CRC is implemented for the
+    given polynomial in a Galois-type shift register. For larger values of
+    ``data_width``, a similar architecture computes every new bit of the
+    CRC in parallel.
+
+    The ``match_detected`` output may be used to validate data with a trailing
+    CRC (also known as a codeword). If the most recently processed word(s) form
+    the valid CRC of all the previous data since ``start`` was asserted, the
+    CRC register will always take on a fixed value known as the residue.  The
+    ``match_detected`` output indicates whether the CRC register currently
+    contains this residue.
+
+    Parameters
+    ----------
+    parameters : Parameters
+        CRC parameters.
+
+    Attributes
+    ----------
+    start : Signal(), in
+        Assert to indicate the start of a CRC computation, re-initialising
+        the CRC register to the initial value. May be asserted simultaneously
+        with ``valid`` or by itself.
+    data : Signal(data_width), in
+        Data word to add to CRC when ``valid`` is asserted.
+    valid : Signal(), in
+        Assert when ``data`` is valid to add the data word to the CRC.
+    crc : Signal(crc_width), out
+        Registered CRC output value, updated one clock cycle after ``valid``
+        becomes asserted.
+    match_detected : Signal(), out
+        Asserted if the current CRC value indicates a valid codeword has been
+        received.
+    """
+    def __init__(self, parameters):
+        if not isinstance(parameters, Parameters):
+            raise TypeError("Algorithmn parameters must be of type Parameters, "
+                            "not {!r}"
+                            .format(parameters))
+        self._crc_width = parameters._crc_width
+        self._data_width = parameters._data_width
+        self._polynomial = parameters._polynomial
+        self._initial_crc = Const(parameters._initial_crc, self._crc_width)
+        self._reflect_input = parameters._reflect_input
+        self._reflect_output = parameters._reflect_output
+        self._xor_output = parameters._xor_output
+        self._matrix_f, self._matrix_g = parameters._matrices()
+        self._residue = parameters.residue()
+
+        self.start = Signal()
+        self.data = Signal(self._data_width)
+        self.valid = Signal()
+        self.crc = Signal(self._crc_width)
+        self.match_detected = Signal()
+
+    def elaborate(self, platform):
+        m = Module()
+
+        crc_reg = Signal(self._crc_width, reset=self._initial_crc.value)
+        data_in = Signal(self._data_width)
+
+        # Optionally bit-reflect input words.
+        if self._reflect_input:
+            m.d.comb += data_in.eq(self.data[::-1])
+        else:
+            m.d.comb += data_in.eq(self.data)
+
+        # Optionally bit-reflect and then XOR the output.
+        if self._reflect_output:
+            m.d.comb += self.crc.eq(crc_reg[::-1] ^ self._xor_output)
+        else:
+            m.d.comb += self.crc.eq(crc_reg ^ self._xor_output)
+
+        # Compute next CRC state.
+        source = Mux(self.start, self._initial_crc, crc_reg)
+        with m.If(self.valid):
+            for i in range(self._crc_width):
+                bit = 0
+                for j in range(self._crc_width):
+                    if self._matrix_f[j][i]:
+                        bit ^= source[j]
+                for j in range(self._data_width):
+                    if self._matrix_g[j][i]:
+                        bit ^= data_in[j]
+                m.d.sync += crc_reg[i].eq(bit)
+        with m.Elif(self.start):
+            m.d.sync += crc_reg.eq(self._initial_crc)
+
+        # Check for residue match, indicating a valid codeword.
+        if self._reflect_output:
+            m.d.comb += self.match_detected.eq(crc_reg[::-1] == self._residue)
+        else:
+            m.d.comb += self.match_detected.eq(crc_reg == self._residue)
+
+        return m
+
+
+# Imported after Algorithm is defined to prevent circular imports.
+from . import catalog
diff --git a/amaranth/lib/crc/catalog.py b/amaranth/lib/crc/catalog.py
new file mode 100644
index 0000000..d5debe7
--- /dev/null
+++ b/amaranth/lib/crc/catalog.py
@@ -0,0 +1,918 @@
+"""
+This module contains a catalog of predefined CRC algorithms.
+
+All entries are from `reveng`_, accessed on 2023-05-25.
+
+    .. _reveng: https://reveng.sourceforge.io/crc-catalogue/all.htm
+
+To use an entry, call it with an optional ``data_width`` which defaults
+to 8. For example:
+
+.. code-block::
+
+    crc8 = m.submodules.crc8 = crc.catalog.CRC8_AUTOSAR().create()
+
+"""
+
+from . import Algorithm
+
+# Note: The trailing `#:` gives Sphinx an empty documentation string for each
+# constant, allowing it to be documented with `automodule` (which otherwise
+# ignores undocumented module constants) and also preventing it from using
+# the Algorithm docstring if otherwise forced to document the constants.
+
+CRC3_GSM = Algorithm(
+    crc_width=3,
+    polynomial=0x3,
+    initial_crc=0x0,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x7)  #:
+
+CRC3_ROHC = Algorithm(
+    crc_width=3,
+    polynomial=0x3,
+    initial_crc=0x7,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0)  #:
+
+CRC4_G_704 = CRC4_ITU = Algorithm(
+    crc_width=4,
+    polynomial=0x3,
+    initial_crc=0x0,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0)  #:
+
+CRC4_INTERLAKEN = Algorithm(
+    crc_width=4,
+    polynomial=0x3,
+    initial_crc=0xf,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xf)  #:
+
+CRC5_EPC_C1G2 = CRC5_EPC = Algorithm(
+    crc_width=5,
+    polynomial=0x09,
+    initial_crc=0x09,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC5_G_704 = CRC5_ITU = Algorithm(
+    crc_width=5,
+    polynomial=0x15,
+    initial_crc=0x00,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC5_USB = Algorithm(
+    crc_width=5,
+    polynomial=0x05,
+    initial_crc=0x1f,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x1f)  #:
+
+CRC6_CDMA2000_A = Algorithm(
+    crc_width=6,
+    polynomial=0x27,
+    initial_crc=0x3f,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC6_CDMA2000_B = Algorithm(
+    crc_width=6,
+    polynomial=0x07,
+    initial_crc=0x3f,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC6_DARC = Algorithm(
+    crc_width=6,
+    polynomial=0x19,
+    initial_crc=0x00,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC6_G_704 = CRC6_ITU = Algorithm(
+    crc_width=6,
+    polynomial=0x03,
+    initial_crc=0x00,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC6_GSM = Algorithm(
+    crc_width=6,
+    polynomial=0x2f,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x3f)  #:
+
+CRC7_MMC = Algorithm(
+    crc_width=7,
+    polynomial=0x09,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC7_ROHC = Algorithm(
+    crc_width=7,
+    polynomial=0x4f,
+    initial_crc=0x7f,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC7_UMTS = Algorithm(
+    crc_width=7,
+    polynomial=0x45,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_AUTOSAR = Algorithm(
+    crc_width=8,
+    polynomial=0x2f,
+    initial_crc=0xff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xff)  #:
+
+CRC8_BLUETOOTH = Algorithm(
+    crc_width=8,
+    polynomial=0xa7,
+    initial_crc=0x00,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC8_CDMA2000 = Algorithm(
+    crc_width=8,
+    polynomial=0x9b,
+    initial_crc=0xff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_DARC = Algorithm(
+    crc_width=8,
+    polynomial=0x39,
+    initial_crc=0x00,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC8_DVB_S2 = Algorithm(
+    crc_width=8,
+    polynomial=0xd5,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_GSM_A = Algorithm(
+    crc_width=8,
+    polynomial=0x1d,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_GSM_B = Algorithm(
+    crc_width=8,
+    polynomial=0x49,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xff)  #:
+
+CRC8_HITAG = Algorithm(
+    crc_width=8,
+    polynomial=0x1d,
+    initial_crc=0xff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_I_432_1 = CRC8_ITU = Algorithm(
+    crc_width=8,
+    polynomial=0x07,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x55)  #:
+
+CRC8_I_CODE = Algorithm(
+    crc_width=8,
+    polynomial=0x1d,
+    initial_crc=0xfd,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_LTE = Algorithm(
+    crc_width=8,
+    polynomial=0x9b,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_MAXIM_DOW = CRC8_MAXIM = Algorithm(
+    crc_width=8,
+    polynomial=0x31,
+    initial_crc=0x00,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC8_MIFARE_MAD = Algorithm(
+    crc_width=8,
+    polynomial=0x1d,
+    initial_crc=0xc7,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_NRSC_5 = Algorithm(
+    crc_width=8,
+    polynomial=0x31,
+    initial_crc=0xff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_OPENSAFETY = Algorithm(
+    crc_width=8,
+    polynomial=0x2f,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_ROHC = Algorithm(
+    crc_width=8,
+    polynomial=0x07,
+    initial_crc=0xff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC8_SAE_J1850 = Algorithm(
+    crc_width=8,
+    polynomial=0x1d,
+    initial_crc=0xff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xff)  #:
+
+CRC8_SMBUS = Algorithm(
+    crc_width=8,
+    polynomial=0x07,
+    initial_crc=0x00,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00)  #:
+
+CRC8_TECH_3250 = CRC8_AES = CRC8_ETU = Algorithm(
+    crc_width=8,
+    polynomial=0x1d,
+    initial_crc=0xff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC8_WCDMA = Algorithm(
+    crc_width=8,
+    polynomial=0x9b,
+    initial_crc=0x00,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00)  #:
+
+CRC10_ATM = CRC10_I_610 = Algorithm(
+    crc_width=10,
+    polynomial=0x233,
+    initial_crc=0x000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000)  #:
+
+CRC10_CDMA2000 = Algorithm(
+    crc_width=10,
+    polynomial=0x3d9,
+    initial_crc=0x3ff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000)  #:
+
+CRC10_GSM = Algorithm(
+    crc_width=10,
+    polynomial=0x175,
+    initial_crc=0x000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x3ff)  #:
+
+CRC11_FLEXRAY = Algorithm(
+    crc_width=11,
+    polynomial=0x385,
+    initial_crc=0x01a,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000)  #:
+
+CRC11_UMTS = Algorithm(
+    crc_width=11,
+    polynomial=0x307,
+    initial_crc=0x000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000)  #:
+
+CRC12_CDMA2000 = Algorithm(
+    crc_width=12,
+    polynomial=0xf13,
+    initial_crc=0xfff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000)  #:
+
+CRC12_DECT = Algorithm(
+    crc_width=12,
+    polynomial=0x80f,
+    initial_crc=0x000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000)  #:
+
+CRC12_GSM = Algorithm(
+    crc_width=12,
+    polynomial=0xd31,
+    initial_crc=0x000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xfff)  #:
+
+CRC12_UMTS = CRC12_3GPP = Algorithm(
+    crc_width=12,
+    polynomial=0x80f,
+    initial_crc=0x000,
+    reflect_input=False,
+    reflect_output=True,
+    xor_output=0x000)  #:
+
+CRC13_BBC = Algorithm(
+    crc_width=13,
+    polynomial=0x1cf5,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC14_DARC = Algorithm(
+    crc_width=14,
+    polynomial=0x0805,
+    initial_crc=0x0000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC14_GSM = Algorithm(
+    crc_width=14,
+    polynomial=0x202d,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x3fff)  #:
+
+CRC15_CAN = Algorithm(
+    crc_width=15,
+    polynomial=0x4599,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC15_MPT1327 = Algorithm(
+    crc_width=15,
+    polynomial=0x6815,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0001)  #:
+
+CRC16_ARC = CRC16_IBM = Algorithm(
+    crc_width=16,
+    polynomial=0x8005,
+    initial_crc=0x0000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_CDMA2000 = Algorithm(
+    crc_width=16,
+    polynomial=0xc867,
+    initial_crc=0xffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_CMS = Algorithm(
+    crc_width=16,
+    polynomial=0x8005,
+    initial_crc=0xffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_DDS_110 = Algorithm(
+    crc_width=16,
+    polynomial=0x8005,
+    initial_crc=0x800d,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_DECT_R = Algorithm(
+    crc_width=16,
+    polynomial=0x0589,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0001)  #:
+
+CRC16_DECT_X = Algorithm(
+    crc_width=16,
+    polynomial=0x0589,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_DNP = Algorithm(
+    crc_width=16,
+    polynomial=0x3d65,
+    initial_crc=0x0000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffff)  #:
+
+CRC16_EN_13757 = Algorithm(
+    crc_width=16,
+    polynomial=0x3d65,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffff)  #:
+
+CRC16_GENIBUS = CRC16_DARC = CRC16_EPC = CRC16_EPC_C1G2 = CRC16_I_CODE = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0xffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffff)  #:
+
+CRC16_GSM = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffff)  #:
+
+CRC16_IBM_3740 = CRC16_AUTOSAR = CRC16_CCITT_FALSE = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0xffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_IBM_SDLC = CRC16_ISO_HDLC = CRC16_ISO_IEC_14443_3_B = CRC16_X25 = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0xffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffff)  #:
+
+CRC16_ISO_IEC_14443_3_A = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0xc6c6,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_KERMIT = CRC16_BLUETOOTH = CRC16_CCITT = CRC16_CCITT_TRUE = CRC16_V_41_LSB = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0x0000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_LJ1200 = Algorithm(
+    crc_width=16,
+    polynomial=0x6f63,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_M17 = Algorithm(
+    crc_width=16,
+    polynomial=0x5935,
+    initial_crc=0xffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_MAXIM_DOW = CRC16_MAXIM = Algorithm(
+    crc_width=16,
+    polynomial=0x8005,
+    initial_crc=0x0000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffff)  #:
+
+CRC16_MCRF4XX = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0xffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_MODBUS = Algorithm(
+    crc_width=16,
+    polynomial=0x8005,
+    initial_crc=0xffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_NRSC_5 = Algorithm(
+    crc_width=16,
+    polynomial=0x080b,
+    initial_crc=0xffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_OPENSAFETY_A = Algorithm(
+    crc_width=16,
+    polynomial=0x5935,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_OPENSAFETY_B = Algorithm(
+    crc_width=16,
+    polynomial=0x755b,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_PROFIBUS = CRC16_IEC_61158_2 = Algorithm(
+    crc_width=16,
+    polynomial=0x1dcf,
+    initial_crc=0xffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffff)  #:
+
+CRC16_RIELLO = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0xb2aa,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_SPI_FUJITSU = CRC16_AUG_CCITT = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0x1d0f,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_T10_DIF = Algorithm(
+    crc_width=16,
+    polynomial=0x8bb7,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_TELEDISK = Algorithm(
+    crc_width=16,
+    polynomial=0xa097,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_TMS37157 = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0x89ec,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000)  #:
+
+CRC16_UMTS = CRC16_BUYPASS = CRC16_VERIFONE = Algorithm(
+    crc_width=16,
+    polynomial=0x8005,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC16_USB = Algorithm(
+    crc_width=16,
+    polynomial=0x8005,
+    initial_crc=0xffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffff)  #:
+
+CRC16_XMODEM = CRC16_ACORN = CRC16_LTE = CRC16_V_41_MSB = CRC16_ZMODEM = Algorithm(
+    crc_width=16,
+    polynomial=0x1021,
+    initial_crc=0x0000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000)  #:
+
+CRC17_CAN_FD = Algorithm(
+    crc_width=17,
+    polynomial=0x1685b,
+    initial_crc=0x00000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00000)  #:
+
+CRC21_CAN_FD = Algorithm(
+    crc_width=21,
+    polynomial=0x102899,
+    initial_crc=0x000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000000)  #:
+
+CRC24_BLE = Algorithm(
+    crc_width=24,
+    polynomial=0x00065b,
+    initial_crc=0x555555,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x000000)  #:
+
+CRC24_FLEXRAY_A = Algorithm(
+    crc_width=24,
+    polynomial=0x5d6dcb,
+    initial_crc=0xfedcba,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000000)  #:
+
+CRC24_FLEXRAY_B = Algorithm(
+    crc_width=24,
+    polynomial=0x5d6dcb,
+    initial_crc=0xabcdef,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000000)  #:
+
+CRC24_INTERLAKEN = Algorithm(
+    crc_width=24,
+    polynomial=0x328b63,
+    initial_crc=0xffffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffffff)  #:
+
+CRC24_LTE_A = Algorithm(
+    crc_width=24,
+    polynomial=0x864cfb,
+    initial_crc=0x000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000000)  #:
+
+CRC24_LTE_B = Algorithm(
+    crc_width=24,
+    polynomial=0x800063,
+    initial_crc=0x000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000000)  #:
+
+CRC24_OPENPGP = Algorithm(
+    crc_width=24,
+    polynomial=0x864cfb,
+    initial_crc=0xb704ce,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x000000)  #:
+
+CRC24_OS_9 = Algorithm(
+    crc_width=24,
+    polynomial=0x800063,
+    initial_crc=0xffffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffffff)  #:
+
+CRC30_CDMA = Algorithm(
+    crc_width=30,
+    polynomial=0x2030b9c7,
+    initial_crc=0x3fffffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x3fffffff)  #:
+
+CRC31_PHILIPS = Algorithm(
+    crc_width=31,
+    polynomial=0x04c11db7,
+    initial_crc=0x7fffffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x7fffffff)  #:
+
+CRC32_AIXM = Algorithm(
+    crc_width=32,
+    polynomial=0x814141ab,
+    initial_crc=0x00000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00000000)  #:
+
+CRC32_AUTOSAR = Algorithm(
+    crc_width=32,
+    polynomial=0xf4acfb13,
+    initial_crc=0xffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffffffff)  #:
+
+CRC32_BASE91_D = Algorithm(
+    crc_width=32,
+    polynomial=0xa833982b,
+    initial_crc=0xffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffffffff)  #:
+
+CRC32_BZIP2 = CRC32_AAL5 = CRC32_DECT_B = Algorithm(
+    crc_width=32,
+    polynomial=0x04c11db7,
+    initial_crc=0xffffffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffffffff)  #:
+
+CRC32_CD_ROM_EDC = Algorithm(
+    crc_width=32,
+    polynomial=0x8001801b,
+    initial_crc=0x00000000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00000000)  #:
+
+CRC32_CKSUM = CRC32_POSIX = Algorithm(
+    crc_width=32,
+    polynomial=0x04c11db7,
+    initial_crc=0x00000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffffffff)  #:
+
+CRC32_ISCSI = CRC32_BASE91_C = CRC32_CASTAGNOLI = CRC32_INTERLAKEN = Algorithm(
+    crc_width=32,
+    polynomial=0x1edc6f41,
+    initial_crc=0xffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffffffff)  #:
+
+CRC32_ISO_HDLC = CRC32_ADCCP = CRC32_V_42 = CRC32_XZ = CRC32_PKZIP = CRC32_ETHERNET = Algorithm(
+    crc_width=32,
+    polynomial=0x04c11db7,
+    initial_crc=0xffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffffffff)  #:
+
+CRC32_JAMCRC = Algorithm(
+    crc_width=32,
+    polynomial=0x04c11db7,
+    initial_crc=0xffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00000000)  #:
+
+CRC32_MEF = Algorithm(
+    crc_width=32,
+    polynomial=0x741b8cd7,
+    initial_crc=0xffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x00000000)  #:
+
+CRC32_MPEG_2 = Algorithm(
+    crc_width=32,
+    polynomial=0x04c11db7,
+    initial_crc=0xffffffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00000000)  #:
+
+CRC32_XFER = Algorithm(
+    crc_width=32,
+    polynomial=0x000000af,
+    initial_crc=0x00000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x00000000)  #:
+
+CRC40_GSM = Algorithm(
+    crc_width=40,
+    polynomial=0x0004820009,
+    initial_crc=0x0000000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffffffffff)  #:
+
+CRC64_ECMA_182 = Algorithm(
+    crc_width=64,
+    polynomial=0x42f0e1eba9ea3693,
+    initial_crc=0x0000000000000000,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0x0000000000000000)  #:
+
+CRC64_GO_ISO = Algorithm(
+    crc_width=64,
+    polynomial=0x000000000000001b,
+    initial_crc=0xffffffffffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffffffffffffffff)  #:
+
+CRC64_MS = Algorithm(
+    crc_width=64,
+    polynomial=0x259c84cba6426349,
+    initial_crc=0xffffffffffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000000000000000)  #:
+
+CRC64_REDIS = Algorithm(
+    crc_width=64,
+    polynomial=0xad93d23594c935a9,
+    initial_crc=0x0000000000000000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x0000000000000000)  #:
+
+CRC64_WE = Algorithm(
+    crc_width=64,
+    polynomial=0x42f0e1eba9ea3693,
+    initial_crc=0xffffffffffffffff,
+    reflect_input=False,
+    reflect_output=False,
+    xor_output=0xffffffffffffffff)  #:
+
+CRC64_XZ = CRC64_ECMA = Algorithm(
+    crc_width=64,
+    polynomial=0x42f0e1eba9ea3693,
+    initial_crc=0xffffffffffffffff,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0xffffffffffffffff)  #:
+
+CRC82_DARC = Algorithm(
+    crc_width=82,
+    polynomial=0x0308c0111011401440411,
+    initial_crc=0x000000000000000000000,
+    reflect_input=True,
+    reflect_output=True,
+    xor_output=0x000000000000000000000)  #:
diff --git a/docs/changes.rst b/docs/changes.rst
index f27ec26..261f6c1 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -35,6 +35,9 @@ Implemented RFCs
 .. _RFC 3: https://amaranth-lang.org/rfcs/0003-enumeration-shapes.html
 .. _RFC 4: https://amaranth-lang.org/rfcs/0004-const-castable-exprs.html
 .. _RFC 5: https://amaranth-lang.org/rfcs/0005-remove-const-normalize.html
+.. _RFC 6: https://amaranth-lang.org/rfcs/0006-stdlib-crc.html
+.. _RFC 8: https://amaranth-lang.org/rfcs/0008-aggregate-extensibility.html
+.. _RFC 9: https://amaranth-lang.org/rfcs/0009-const-init-shape-castable.html
 .. _RFC 8: https://amaranth-lang.org/rfcs/0008-aggregate-extensibility.html
 .. _RFC 9: https://amaranth-lang.org/rfcs/0009-const-init-shape-castable.html
 .. _RFC 10: https://amaranth-lang.org/rfcs/0010-move-repl-to-value.html
@@ -44,6 +47,9 @@ Implemented RFCs
 * `RFC 3`_: Enumeration shapes
 * `RFC 4`_: Constant-castable expressions
 * `RFC 5`_: Remove Const.normalize
+* `RFC 6`_: CRC generator
+* `RFC 8`_: Aggregate extensibility
+* `RFC 9`_: Constant initialization for shape-castable objects
 * `RFC 8`_: Aggregate extensibility
 * `RFC 9`_: Constant initialization for shape-castable objects
 * `RFC 10`_: Move Repl to Value.replicate
@@ -79,6 +85,7 @@ Standard library changes
 
 * Added: :mod:`amaranth.lib.enum`. (`RFC 3`_)
 * Added: :mod:`amaranth.lib.data`. (`RFC 1`_)
+* Added: :mod:`amaranth.lib.crc`. (`RFC 6`_)
 
 
 Toolchain changes
diff --git a/docs/stdlib.rst b/docs/stdlib.rst
index 2140381..48a7930 100644
--- a/docs/stdlib.rst
+++ b/docs/stdlib.rst
@@ -12,4 +12,5 @@ Standard library
    stdlib/data
    stdlib/coding
    stdlib/cdc
+   stdlib/crc
    stdlib/fifo
diff --git a/docs/stdlib/crc.rst b/docs/stdlib/crc.rst
new file mode 100644
index 0000000..96e8757
--- /dev/null
+++ b/docs/stdlib/crc.rst
@@ -0,0 +1,11 @@
+Cyclic redundancy checks
+########################
+
+.. automodule:: amaranth.lib.crc
+   :special-members: __call__
+
+The following pre-defined CRC algorithms are available:
+
+.. toctree::
+
+   crc/catalog
diff --git a/docs/stdlib/crc/catalog.rst b/docs/stdlib/crc/catalog.rst
new file mode 100644
index 0000000..1f8a575
--- /dev/null
+++ b/docs/stdlib/crc/catalog.rst
@@ -0,0 +1,4 @@
+Predefined CRC Algorithms
+#########################
+
+.. automodule:: amaranth.lib.crc.catalog


Test patch:
diff --git a/tests/test_lib_crc.py b/tests/test_lib_crc.py
new file mode 100644
index 0000000..db06442
--- /dev/null
+++ b/tests/test_lib_crc.py
@@ -0,0 +1,350 @@
+# amaranth: UnusedElaboratable=no
+
+import unittest
+
+from amaranth.sim import *
+from amaranth.lib.crc import Algorithm, Processor, catalog
+
+
+# Subset of catalogue CRCs used to test the hardware CRC implementation,
+# as testing all algorithms takes a long time for little benefit.
+# Selected to ensure coverage of CRC width, initial value, reflection, and
+# XOR output.
+CRCS = [
+    "CRC3_GSM", "CRC4_INTERLAKEN", "CRC5_USB", "CRC8_AUTOSAR", "CRC8_BLUETOOTH",
+    "CRC8_I_432_1", "CRC12_UMTS", "CRC15_CAN", "CRC16_ARC", "CRC16_IBM_3740",
+    "CRC17_CAN_FD", "CRC21_CAN_FD", "CRC24_FLEXRAY_A", "CRC32_AUTOSAR",
+    "CRC32_BZIP2", "CRC32_ISO_HDLC", "CRC40_GSM"
+]
+
+# All catalogue CRCs with their associated check values and residues from
+# the reveng catalogue. Used to verify our computation of the check and
+# residue values.
+CRC_CHECKS = {
+    "CRC3_GSM": (0x4, 0x2),
+    "CRC3_ROHC": (0x6, 0x0),
+    "CRC4_G_704": (0x7, 0x0),
+    "CRC4_ITU": (0x7, 0x0),
+    "CRC4_INTERLAKEN": (0xb, 0x2),
+    "CRC5_EPC_C1G2": (0x00, 0x00),
+    "CRC5_EPC": (0x00, 0x00),
+    "CRC5_G_704": (0x07, 0x00),
+    "CRC5_ITU": (0x07, 0x00),
+    "CRC5_USB": (0x19, 0x06),
+    "CRC6_CDMA2000_A": (0x0d, 0x00),
+    "CRC6_CDMA2000_B": (0x3b, 0x00),
+    "CRC6_DARC": (0x26, 0x00),
+    "CRC6_G_704": (0x06, 0x00),
+    "CRC6_ITU": (0x06, 0x00),
+    "CRC6_GSM": (0x13, 0x3a),
+    "CRC7_MMC": (0x75, 0x00),
+    "CRC7_ROHC": (0x53, 0x00),
+    "CRC7_UMTS": (0x61, 0x00),
+    "CRC8_AUTOSAR": (0xdf, 0x42),
+    "CRC8_BLUETOOTH": (0x26, 0x00),
+    "CRC8_CDMA2000": (0xda, 0x00),
+    "CRC8_DARC": (0x15, 0x00),
+    "CRC8_DVB_S2": (0xbc, 0x00),
+    "CRC8_GSM_A": (0x37, 0x00),
+    "CRC8_GSM_B": (0x94, 0x53),
+    "CRC8_HITAG": (0xb4, 0x00),
+    "CRC8_I_432_1": (0xa1, 0xac),
+    "CRC8_ITU": (0xa1, 0xac),
+    "CRC8_I_CODE": (0x7e, 0x00),
+    "CRC8_LTE": (0xea, 0x00),
+    "CRC8_MAXIM_DOW": (0xa1, 0x00),
+    "CRC8_MAXIM": (0xa1, 0x00),
+    "CRC8_MIFARE_MAD": (0x99, 0x00),
+    "CRC8_NRSC_5": (0xf7, 0x00),
+    "CRC8_OPENSAFETY": (0x3e, 0x00),
+    "CRC8_ROHC": (0xd0, 0x00),
+    "CRC8_SAE_J1850": (0x4b, 0xc4),
+    "CRC8_SMBUS": (0xf4, 0x00),
+    "CRC8_TECH_3250": (0x97, 0x00),
+    "CRC8_AES": (0x97, 0x00),
+    "CRC8_ETU": (0x97, 0x00),
+    "CRC8_WCDMA": (0x25, 0x00),
+    "CRC10_ATM": (0x199, 0x000),
+    "CRC10_I_610": (0x199, 0x000),
+    "CRC10_CDMA2000": (0x233, 0x000),
+    "CRC10_GSM": (0x12a, 0x0c6),
+    "CRC11_FLEXRAY": (0x5a3, 0x000),
+    "CRC11_UMTS": (0x061, 0x000),
+    "CRC12_CDMA2000": (0xd4d, 0x000),
+    "CRC12_DECT": (0xf5b, 0x000),
+    "CRC12_GSM": (0xb34, 0x178),
+    "CRC12_UMTS": (0xdaf, 0x000),
+    "CRC12_3GPP": (0xdaf, 0x000),
+    "CRC13_BBC": (0x04fa, 0x0000),
+    "CRC14_DARC": (0x082d, 0x0000),
+    "CRC14_GSM": (0x30ae, 0x031e),
+    "CRC15_CAN": (0x059e, 0x0000),
+    "CRC15_MPT1327": (0x2566, 0x6815),
+    "CRC16_ARC": (0xbb3d, 0x0000),
+    "CRC16_IBM": (0xbb3d, 0x0000),
+    "CRC16_CDMA2000": (0x4c06, 0x0000),
+    "CRC16_CMS": (0xaee7, 0x0000),
+    "CRC16_DDS_110": (0x9ecf, 0x0000),
+    "CRC16_DECT_R": (0x007e, 0x0589),
+    "CRC16_DECT_X": (0x007f, 0x0000),
+    "CRC16_DNP": (0xea82, 0x66c5),
+    "CRC16_EN_13757": (0xc2b7, 0xa366),
+    "CRC16_GENIBUS": (0xd64e, 0x1d0f),
+    "CRC16_DARC": (0xd64e, 0x1d0f),
+    "CRC16_EPC": (0xd64e, 0x1d0f),
+    "CRC16_EPC_C1G2": (0xd64e, 0x1d0f),
+    "CRC16_I_CODE": (0xd64e, 0x1d0f),
+    "CRC16_GSM": (0xce3c, 0x1d0f),
+    "CRC16_IBM_3740": (0x29b1, 0x0000),
+    "CRC16_AUTOSAR": (0x29b1, 0x0000),
+    "CRC16_CCITT_FALSE": (0x29b1, 0x0000),
+    "CRC16_IBM_SDLC": (0x906e, 0xf0b8),
+    "CRC16_ISO_HDLC": (0x906e, 0xf0b8),
+    "CRC16_ISO_IEC_14443_3_B": (0x906e, 0xf0b8),
+    "CRC16_X25": (0x906e, 0xf0b8),
+    "CRC16_ISO_IEC_14443_3_A": (0xbf05, 0x0000),
+    "CRC16_KERMIT": (0x2189, 0x0000),
+    "CRC16_BLUETOOTH": (0x2189, 0x0000),
+    "CRC16_CCITT": (0x2189, 0x0000),
+    "CRC16_CCITT_TRUE": (0x2189, 0x0000),
+    "CRC16_V_41_LSB": (0x2189, 0x0000),
+    "CRC16_LJ1200": (0xbdf4, 0x0000),
+    "CRC16_M17": (0x772b, 0x0000),
+    "CRC16_MAXIM_DOW": (0x44c2, 0xb001),
+    "CRC16_MAXIM": (0x44c2, 0xb001),
+    "CRC16_MCRF4XX": (0x6f91, 0x0000),
+    "CRC16_MODBUS": (0x4b37, 0x0000),
+    "CRC16_NRSC_5": (0xa066, 0x0000),
+    "CRC16_OPENSAFETY_A": (0x5d38, 0x0000),
+    "CRC16_OPENSAFETY_B": (0x20fe, 0x0000),
+    "CRC16_PROFIBUS": (0xa819, 0xe394),
+    "CRC16_IEC_61158_2": (0xa819, 0xe394),
+    "CRC16_RIELLO": (0x63d0, 0x0000),
+    "CRC16_SPI_FUJITSU": (0xe5cc, 0x0000),
+    "CRC16_AUG_CCITT": (0xe5cc, 0x0000),
+    "CRC16_T10_DIF": (0xd0db, 0x0000),
+    "CRC16_TELEDISK": (0x0fb3, 0x0000),
+    "CRC16_TMS37157": (0x26b1, 0x0000),
+    "CRC16_UMTS": (0xfee8, 0x0000),
+    "CRC16_BUYPASS": (0xfee8, 0x0000),
+    "CRC16_VERIFONE": (0xfee8, 0x0000),
+    "CRC16_USB": (0xb4c8, 0xb001),
+    "CRC16_XMODEM": (0x31c3, 0x0000),
+    "CRC16_ACORN": (0x31c3, 0x0000),
+    "CRC16_LTE": (0x31c3, 0x0000),
+    "CRC16_V_41_MSB": (0x31c3, 0x0000),
+    "CRC16_ZMODEM": (0x31c3, 0x0000),
+    "CRC17_CAN_FD": (0x04f03, 0x00000),
+    "CRC21_CAN_FD": (0x0ed841, 0x000000),
+    "CRC24_BLE": (0xc25a56, 0x000000),
+    "CRC24_FLEXRAY_A": (0x7979bd, 0x000000),
+    "CRC24_FLEXRAY_B": (0x1f23b8, 0x000000),
+    "CRC24_INTERLAKEN": (0xb4f3e6, 0x144e63),
+    "CRC24_LTE_A": (0xcde703, 0x000000),
+    "CRC24_LTE_B": (0x23ef52, 0x000000),
+    "CRC24_OPENPGP": (0x21cf02, 0x000000),
+    "CRC24_OS_9": (0x200fa5, 0x800fe3),
+    "CRC30_CDMA": (0x04c34abf, 0x34efa55a),
+    "CRC31_PHILIPS": (0x0ce9e46c, 0x4eaf26f1),
+    "CRC32_AIXM": (0x3010bf7f, 0x00000000),
+    "CRC32_AUTOSAR": (0x1697d06a, 0x904cddbf),
+    "CRC32_BASE91_D": (0x87315576, 0x45270551),
+    "CRC32_BZIP2": (0xfc891918, 0xc704dd7b),
+    "CRC32_AAL5": (0xfc891918, 0xc704dd7b),
+    "CRC32_DECT_B": (0xfc891918, 0xc704dd7b),
+    "CRC32_CD_ROM_EDC": (0x6ec2edc4, 0x00000000),
+    "CRC32_CKSUM": (0x765e7680, 0xc704dd7b),
+    "CRC32_POSIX": (0x765e7680, 0xc704dd7b),
+    "CRC32_ISCSI": (0xe3069283, 0xb798b438),
+    "CRC32_BASE91_C": (0xe3069283, 0xb798b438),
+    "CRC32_CASTAGNOLI": (0xe3069283, 0xb798b438),
+    "CRC32_INTERLAKEN": (0xe3069283, 0xb798b438),
+    "CRC32_ISO_HDLC": (0xcbf43926, 0xdebb20e3),
+    "CRC32_ADCCP": (0xcbf43926, 0xdebb20e3),
+    "CRC32_V_42": (0xcbf43926, 0xdebb20e3),
+    "CRC32_XZ": (0xcbf43926, 0xdebb20e3),
+    "CRC32_PKZIP": (0xcbf43926, 0xdebb20e3),
+    "CRC32_ETHERNET": (0xcbf43926, 0xdebb20e3),
+    "CRC32_JAMCRC": (0x340bc6d9, 0x00000000),
+    "CRC32_MEF": (0xd2c22f51, 0x00000000),
+    "CRC32_MPEG_2": (0x0376e6e7, 0x00000000),
+    "CRC32_XFER": (0xbd0be338, 0x00000000),
+    "CRC40_GSM": (0xd4164fc646, 0xc4ff8071ff),
+    "CRC64_ECMA_182": (0x6c40df5f0b497347, 0x0000000000000000),
+    "CRC64_GO_ISO": (0xb90956c775a41001, 0x5300000000000000),
+    "CRC64_MS": (0x75d4b74f024eceea, 0x0000000000000000),
+    "CRC64_REDIS": (0xe9c6d914c4b8d9ca, 0x0000000000000000),
+    "CRC64_WE": (0x62ec59e3f1a4f00a, 0xfcacbebd5931a992),
+    "CRC64_XZ": (0x995dc9bbdf1939fa, 0x49958c9abd7d353f),
+    "CRC64_ECMA": (0x995dc9bbdf1939fa, 0x49958c9abd7d353f),
+    "CRC82_DARC": (0x09ea83f625023801fd612, 0x000000000000000000000),
+}
+
+
+class CRCTestCase(unittest.TestCase):
+    def test_checks(self):
+        """
+        Verify computed check values and residues match catalogue entries.
+        """
+        for name in dir(catalog):
+            if name.startswith("CRC"):
+                crc = getattr(catalog, name)(data_width=8)
+                check, residue = CRC_CHECKS[name]
+                assert crc.compute(b"123456789") == check
+                assert crc.residue() == residue
+
+    def test_repr(self):
+        algorithm = catalog.CRC8_AUTOSAR
+        assert repr(algorithm) == "Algorithm(crc_width=8, polynomial=0x2f," \
+            " initial_crc=0xff, reflect_input=False, reflect_output=False," \
+            " xor_output=0xff)"
+
+        params = algorithm(data_width=8)
+        assert repr(params) == "Parameters(Algorithm(crc_width=8," \
+            " polynomial=0x2f, initial_crc=0xff, reflect_input=False," \
+            " reflect_output=False, xor_output=0xff), data_width=8)"
+
+    def test_processor_typecheck(self):
+        with self.assertRaises(TypeError):
+            proc = Processor(12)
+
+    def test_algorithm_range_checks(self):
+        with self.assertRaises(ValueError):
+            Algorithm(crc_width=0, polynomial=0x3, initial_crc=0x0,
+                      reflect_input=False, reflect_output=False, xor_output=0x7)
+        with self.assertRaises(ValueError):
+            Algorithm(crc_width=3, polynomial=0x8, initial_crc=0x0,
+                      reflect_input=False, reflect_output=False, xor_output=0x7)
+        with self.assertRaises(ValueError):
+            Algorithm(crc_width=3, polynomial=0x3, initial_crc=0x8,
+                      reflect_input=False, reflect_output=False, xor_output=0x7)
+        with self.assertRaises(ValueError):
+            Algorithm(crc_width=3, polynomial=0x3, initial_crc=0x0,
+                      reflect_input=False, reflect_output=False, xor_output=0x8)
+
+    def test_parameter_range_checks(self):
+        with self.assertRaises(ValueError):
+            catalog.CRC8_AUTOSAR(data_width=0)
+        with self.assertRaises(ValueError):
+            crc = catalog.CRC8_AUTOSAR()
+            crc.compute([3, 4, 256])
+
+    def test_crc_bytes(self):
+        """
+        Verify CRC generation by computing the check value for each CRC
+        in the catalogue with byte-sized inputs.
+        """
+        for name in CRCS:
+            crc = getattr(catalog, name)(data_width=8).create()
+            check = CRC_CHECKS[name][0]
+
+            def process():
+                for word in b"123456789":
+                    yield crc.start.eq(word == b"1")
+                    yield crc.data.eq(word)
+                    yield crc.valid.eq(1)
+                    yield
+                yield crc.valid.eq(0)
+                yield
+                self.assertEqual((yield crc.crc), check)
+
+            sim = Simulator(crc)
+            sim.add_sync_process(process)
+            sim.add_clock(1e-6)
+            sim.run()
+
+    def test_crc_words(self):
+        """
+        Verify CRC generation for non-byte-sized data by computing a check
+        value for 1, 2, 4, 16, 32, and 64-bit inputs.
+        """
+        # We can't use the catalogue check value since it requires 8-bit
+        # inputs, so we'll instead use an input of b"12345678".
+        data = b"12345678"
+        # Split data into individual bits. When input is reflected, we have
+        # to reflect each byte first, then form the input words, then let
+        # the CRC module reflect those words, to get the same effective input.
+        bits = "".join(f"{x:08b}" for x in data)
+        bits_r = "".join(f"{x:08b}"[::-1] for x in data)
+
+        for name in CRCS:
+            for m in (1, 2, 4, 16, 32, 64):
+                algo = getattr(catalog, name)
+                crc = algo(data_width=m).create()
+                # Use a SoftwareCRC with byte inputs to compute new checks.
+                swcrc = algo(data_width=8)
+                check = swcrc.compute(data)
+                # Chunk input bits into m-bit words, reflecting if needed.
+                if algo.reflect_input:
+                    d = [bits_r[i : i+m][::-1] for i in range(0, len(bits), m)]
+                else:
+                    d = [bits[i : i+m] for i in range(0, len(bits), m)]
+                words = [int(x, 2) for x in d]
+
+                def process():
+                    yield crc.start.eq(1)
+                    yield
+                    yield crc.start.eq(0)
+                    for word in words:
+                        yield crc.data.eq(word)
+                        yield crc.valid.eq(1)
+                        yield
+                    yield crc.valid.eq(0)
+                    yield
+                    self.assertEqual((yield crc.crc), check)
+
+                sim = Simulator(crc)
+                sim.add_sync_process(process)
+                sim.add_clock(1e-6)
+                sim.run()
+
+    def test_crc_match(self):
+        """Verify match_detected output detects valid codewords."""
+        for name in CRCS:
+            algo = getattr(catalog, name)
+            n = algo.crc_width
+            m = 8 if n % 8 == 0 else 1
+            crc = algo(data_width=m).create()
+            check = CRC_CHECKS[name][0]
+
+            if m == 8:
+                # For CRCs which are multiples of one byte wide, we can easily
+                # append the correct checksum in bytes.
+                check_b = check.to_bytes(n // 8, "little" if algo.reflect_output else "big")
+                words = b"123456789" + check_b
+            else:
+                # For other CRC sizes, use single-bit input data.
+                if algo.reflect_output:
+                    check_b = check.to_bytes((n + 7)//8, "little")
+                    if not algo.reflect_input:
+                        # For cross-endian CRCs, flip the CRC bits separately.
+                        check_b = bytearray(int(f"{x:08b}"[::-1], 2) for x in check_b)
+                else:
+                    shift = 8 - (n % 8)
+                    check_b = (check << shift).to_bytes((n + 7)//8, "big")
+                    # No catalogue CRCs have ref_in but not ref_out.
+                codeword = b"123456789" + check_b
+                words = []
+                for byte in codeword:
+                    if algo.reflect_input:
+                        words += [int(x) for x in f"{byte:08b}"[::-1]]
+                    else:
+                        words += [int(x) for x in f"{byte:08b}"]
+                words = words[:72 + n]
+
+            def process():
+                yield crc.start.eq(1)
+                yield
+                yield crc.start.eq(0)
+                for word in words:
+                    yield crc.data.eq(word)
+                    yield crc.valid.eq(1)
+                    yield
+                yield crc.valid.eq(0)
+                yield
+                self.assertTrue((yield crc.match_detected))
+
+            sim = Simulator(crc)
+            sim.add_sync_process(process)
+            sim.add_clock(1e-6)
+            sim.run()