lib.crc,docs/stdlib/crc: improve consistency with the rest of documentation.

This commit is contained in:
Catherine 2024-04-10 03:11:33 +00:00
parent c68f9e43f9
commit b6f51d269e
4 changed files with 228 additions and 233 deletions

View file

@ -1,155 +1,114 @@
""" import operator
The :mod:`amaranth.lib.crc` module provides 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 * from ... import *
__all__ = ["Algorithm", "Parameters", "Processor", "catalog"] __all__ = ["Algorithm", "Parameters", "Processor", "catalog"]
class Algorithm: class Algorithm:
""" """Essential parameters for cyclic redundancy check computation.
Settings for a CRC algorithm, excluding data width.
The parameter set is based on the Williams model from The parameter set is based on the Williams model from `"A Painless Guide to CRC Error Detection
"A Painless Guide to CRC Error Detection Algorithms": Algorithms" <http://www.ross.net/crc/download/crc_v3.txt>`_.
http://www.ross.net/crc/download/crc_v3.txt
For a reference of standard CRC parameter sets, refer to: For a reference of standard CRC parameter sets, refer to:
* `reveng`_'s catalogue, which uses an identical parameterisation, * `reveng`_'s catalogue, which uses an identical parameterisation;
* `crcmod`_'s list of predefined functions, but remove the leading '1' * `crcmod`_'s list of predefined functions, but remove the leading '1' from the polynominal,
from the polynominal, XOR the "Init-value" with "XOR-out" to obtain XOR the "Init-value" with "XOR-out" to obtain :py:`initial_crc`, and where "Reversed" is
``initial_crc``, and where "Reversed" is True, set both ``reflect_input`` :py:`True`, set both :py:`reflect_input` and :py:`reflect_output` to :py:`True`;
and ``reflect_output`` to True, * `CRC Zoo`_, which contains only polynomials; use the "explicit +1" form of polynomial but
* `CRC Zoo`_, which contains only polynomials; use the "explicit +1" remove the leading '1'.
form of polynomial but remove the leading '1'.
.. _reveng: https://reveng.sourceforge.io/crc-catalogue/all.htm .. _reveng: https://reveng.sourceforge.io/crc-catalogue/all.htm
.. _crcmod: https://crcmod.sourceforge.net/crcmod.predefined.html .. _crcmod: https://crcmod.sourceforge.net/crcmod.predefined.html
.. _CRC Zoo: https://users.ece.cmu.edu/~koopman/crc/ .. _CRC Zoo: https://users.ece.cmu.edu/~koopman/crc/
Many commonly used CRC algorithms are available in the Many commonly used CRC algorithms are available in the :py:mod:`~amaranth.lib.crc.catalog`
:py:mod:`~amaranth.lib.crc.catalog` module, which includes module, which includes all entries in the `reveng catalogue <reveng_>`_.
all entries in the `reveng`_ catalogue.
To create a :py:class:`Parameters` instance, call the :py:class:`Algorithm` The essential parameters on their own cannot be used to perform CRC computation, and must be
object with the required data width, which defaults to 8 bits. combined with a specific data word width. This can be done using :py:`algo(data_width)`, which
returns a :class:`Parameters` object.
Parameters Parameters
---------- ----------
crc_width : int crc_width : :class:`int`
Bit width of CRC word. Also known as "width" in the Williams model. Bit width of CRC word. Also known as "width" in the Williams model.
polynomial : int polynomial : :class:`int`
CRC polynomial to use, ``crc_width`` bits long, without the implicit CRC polynomial to use, :py:`crc_width` bits long, without the implicit :py:`x ** crc_width`
``x**crc_width`` term. Polynomial is always specified with the highest term. Polynomial is always specified with the highest order terms in the most significant
order terms in the most significant bit positions; use bit positions; use :py:`reflect_input` and :py:`reflect_output` to perform a least
``reflect_input`` and ``reflect_output`` to perform a least
significant bit first computation. significant bit first computation.
initial_crc : int initial_crc : :class:`int`
Initial value of CRC register at reset. Most significant bit always Initial value of CRC register at reset. Most significant bit always corresponds to
corresponds to the highest order term in the CRC register. the highest order term in the CRC register.
reflect_input : bool reflect_input : :class:`bool`
If True, the input data words are bit-reflected, so that they are If :py:`True`, the input data words are bit-reflected, so that they are processed least
processed least significant bit first. significant bit first.
reflect_output : bool reflect_output : :class:`bool`
If True, the output CRC is bit-reflected, so the least-significant bit If :py:`True`, the output CRC is bit-reflected, so that the least-significant bit of
of the output is the highest-order bit of the CRC register. the output is the highest-order bit of the CRC register. Note that this reflection is
Note that this reflection is performed over the entire CRC register; performed over the entire CRC register; for transmission you may want to treat the output
for transmission you may want to treat the output as a little-endian as a little-endian multi-word value, so for example the reflected 16-bit output :py:`0x4E4C`
multi-word value, so for example the reflected 16-bit output 0x4E4C would be transmitted as the two octets :py:`0x4C, 0x4E`, each transmitted least significant
would be transmitted as the two octets 0x4C 0x4E, each transmitted bit first.
least significant bit first. xor_output : :class:`int`
xor_output : int The output CRC will be the CRC register XOR'd with this value, applied after any output
The output CRC will be the CRC register XOR'd with this value, applied bit-reflection.
after any output bit-reflection.
""" """
def __init__(self, *, crc_width, polynomial, initial_crc, reflect_input, def __init__(self, *, crc_width, polynomial, initial_crc, reflect_input,
reflect_output, xor_output): reflect_output, xor_output):
self.crc_width = int(crc_width) self.crc_width = operator.index(crc_width)
self.polynomial = int(polynomial) self.polynomial = operator.index(polynomial)
self.initial_crc = int(initial_crc) self.initial_crc = operator.index(initial_crc)
self.reflect_input = bool(reflect_input) self.reflect_input = bool(reflect_input)
self.reflect_output = bool(reflect_output) self.reflect_output = bool(reflect_output)
self.xor_output = int(xor_output) self.xor_output = operator.index(xor_output)
if self.crc_width <= 0: if not self.crc_width > 0:
raise ValueError("crc_width must be greater than 0") raise ValueError("CRC width must be greater than 0")
if not 0 <= self.polynomial < 2 ** self.crc_width: if self.polynomial not in range(2 ** self.crc_width):
raise ValueError("polynomial must be between 0 and 2**crc_width - 1") raise ValueError("Polynomial must be between 0 and (2 ** crc_width - 1)")
if not 0 <= self.initial_crc < 2 ** self.crc_width: if self.initial_crc not in range(2 ** self.crc_width):
raise ValueError("initial_crc must be between 0 and 2**crc_width - 1") raise ValueError("Initial CRC must be between 0 and (2 ** crc_width - 1)")
if not 0 <= self.xor_output < 2 ** self.crc_width: if self.xor_output not in range(2 ** self.crc_width):
raise ValueError("xor_output must be between 0 and 2**crc_width - 1") raise ValueError("XOR output must be between 0 and (2 ** crc_width - 1)")
def __call__(self, data_width=8): def __call__(self, data_width=8):
""" """Combine these essential parameters with a data word width to form complete parameters.
Constructs a :py:class:`Parameters` instance from this
:py:class:`Algorithm` with the specified ``data_width``.
Parameters Returns
---------- -------
data_width : int :class:`Parameters`
Bit width of data words, default 8. :py:`Parameters(self, data_width)`
""" """
return Parameters(self, data_width) return Parameters(self, data_width)
def __repr__(self): def __repr__(self):
return f"Algorithm(crc_width={self.crc_width}," \ return (f"Algorithm(crc_width={self.crc_width}, "
f" polynomial=0x{self.polynomial:0{self.crc_width//4}x}," \ 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"initial_crc=0x{self.initial_crc:0{self.crc_width // 4}x}, "
f" reflect_input={self.reflect_input}," \ f"reflect_input={self.reflect_input}, "
f" reflect_output={self.reflect_output}," \ f"reflect_output={self.reflect_output}, "
f" xor_output=0x{self.xor_output:0{self.crc_width//4}x})" f"xor_output=0x{self.xor_output:0{self.crc_width // 4}x})")
class Parameters: class Parameters:
""" """Complete parameters for cyclic redundancy check computation.
Full set of parameters for a CRC computation.
Contains the settings from :py:class:`Algorithm` and additionally Contains the essential :class:`Algorithm` parameters, plus the data word width.
``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 A :class:`Parameters` object can be used to directly compute CRCs using
:py:meth:`~Parameters.compute` method, or construct a hardware module with the :meth:`~Parameters.compute` method, or to construct a hardware module using
the :py:meth:`~Parameters.create` method. the :meth:`~Parameters.create` method.
Parameters Parameters
---------- ----------
algorithm : Algorithm algorithm : :class:`Algorithm`
CRC algorithm to use. Specifies the CRC width, polynomial, CRC algorithm to use. Specifies the CRC width, polynomial, initial value, whether to
initial value, whether to reflect the input or output words, reflect the input or output words, and any output XOR.
and any output XOR. data_width : :class:`int`
data_width : int
Bit width of data words. Bit width of data words.
""" """
def __init__(self, algorithm, data_width=8): def __init__(self, algorithm, data_width=8):
@ -159,16 +118,12 @@ class Parameters:
self._reflect_input = algorithm.reflect_input self._reflect_input = algorithm.reflect_input
self._reflect_output = algorithm.reflect_output self._reflect_output = algorithm.reflect_output
self._xor_output = algorithm.xor_output self._xor_output = algorithm.xor_output
self._data_width = int(data_width) self.data_width = operator.index(data_width)
if self._data_width <= 0: if not self.data_width > 0:
raise ValueError("data_width must be greater than 0") raise ValueError("Data width must be greater than 0")
@property @property
def algorithm(self): def algorithm(self):
"""
Returns an :py:class:`Algorithm` with the CRC settings from this
instance.
"""
return Algorithm( return Algorithm(
crc_width=self._crc_width, crc_width=self._crc_width,
polynomial=self._polynomial, polynomial=self._polynomial,
@ -178,13 +133,11 @@ class Parameters:
xor_output=self._xor_output) xor_output=self._xor_output)
def residue(self): def residue(self):
""" """Obtain the residual value left in the CRC register after processing a valid trailing CRC.
Compute the residue value for this CRC, which is the value left in the
CRC register after processing any valid codeword. A trailing CRC data word is also known as a codeword."""
""" # Residue is computed by initialising to (possibly reflected) xor_output, feeding crc_width
# Residue is computed by initialising to (possibly reflected) # worth of 0 bits, then taking the (possibly reflected) output without any XOR.
# xor_output, feeding crc_width worth of 0 bits, then taking
# the (possibly reflected) output without any XOR.
if self._reflect_output: if self._reflect_output:
init = self._reflect(self._xor_output, self._crc_width) init = self._reflect(self._xor_output, self._crc_width)
else: else:
@ -193,179 +146,164 @@ class Parameters:
algo.initial_crc = init algo.initial_crc = init
algo.reflect_input = False algo.reflect_input = False
algo.xor_output = 0 algo.xor_output = 0
return algo(data_width=self._crc_width).compute([0]) return algo(self._crc_width).compute([0])
def create(self):
"""
Returns a ``Processor`` configured with these parameters.
"""
return Processor(self)
def compute(self, data): def compute(self, data):
""" """Compute the CRC of all data words in :py:`data`.
Computes and returns the CRC of all data words in ``data``.
Parameters Parameters
---------- ----------
data : iterable of integers data : iterable of :class:`int`
The CRC is computed over this complete set of data. Data words, each of which is :py:`data_width` bits wide.
Each item is an integer of bitwidth equal to ``data_width``.
""" """
# Precompute some constants we use every iteration. # Precompute some constants we use every iteration.
word_max = (1 << self._data_width) - 1 word_max = (1 << self.data_width) - 1
top_bit = 1 << (self._crc_width + self._data_width - 1) top_bit = 1 << (self._crc_width + self.data_width - 1)
crc_mask = (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 poly_shifted = self._polynomial << self.data_width
# Implementation notes: # Implementation notes:
# We always compute most-significant bit first, which means the # We always compute most-significant bit first, which means the polynomial and initial
# polynomial and initial value may be used as-is, and the reflect_in # value may be used as-is, and the reflect_in and reflect_out values have their usual sense.
# 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
# However, when computing word-at-a-time and MSbit-first, we must align # its MSbit lines up with the MSbit of the previous CRC value. When the CRC width is smaller
# the input word so its MSbit lines up with the MSbit of the previous # than the word width, this would normally truncate data bits. Instead, we shift the initial
# CRC value. When the CRC width is smaller than the word width, this # CRC left by the data width, and the data word left by the crc width, lining up their
# would normally truncate data bits. # MSbits no matter the relation between the two widths. The new CRC is then shifted right by
# Instead, we shift the initial CRC left by the data width, and the # the data width before output.
# 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 crc = self._initial_crc << self.data_width
for word in data: for word in data:
if not 0 <= word <= word_max: if not 0 <= word <= word_max:
raise ValueError(f"data word must be between 0 and {word_max - 1}") raise ValueError(f"data word must be between 0 and {word_max - 1}")
if self._reflect_input: if self._reflect_input:
word = self._reflect(word, self._data_width) word = self._reflect(word, self.data_width)
crc ^= word << self._crc_width crc ^= word << self._crc_width
for _ in range(self._data_width): for _ in range(self.data_width):
if crc & top_bit: if crc & top_bit:
crc = (crc << 1) ^ poly_shifted crc = (crc << 1) ^ poly_shifted
else: else:
crc <<= 1 crc <<= 1
crc &= crc_mask crc &= crc_mask
crc >>= self._data_width crc >>= self.data_width
if self._reflect_output: if self._reflect_output:
crc = self._reflect(crc, self._crc_width) crc = self._reflect(crc, self._crc_width)
crc ^= self._xor_output crc ^= self._xor_output
return crc return crc
def create(self):
"""Create a hardware CRC generator with these parameters.
Returns
-------
:class:`Processor`
:py:`Processor(self)`
"""
return Processor(self)
@staticmethod @staticmethod
def _reflect(word, n): def _reflect(word, n):
""" """Bitwise-reflect an :py:`n`-bit word :py:`word`."""
Bitwise-reflects an n-bit word ``word``.
"""
return int(f"{word:0{n}b}"[::-1], 2) return int(f"{word:0{n}b}"[::-1], 2)
def _matrices(self): def _matrices(self):
""" """Compute the F and G matrices for parallel CRC computation.
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 Computes the F and G matrices for parallel CRC computation, treating the CRC as a linear
the first entry, with index (0, 0), corresponds to the effect of the time-invariant system described by the state relation x(t+1) = F.x(i) + G.u(i), where x(i)
least-significant bit of the input on the least-significant bit of the and u(i) are column vectors of the bits of the CRC register and input word, F is the n-by-n
output. 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.
For convenience of implementation, both matrices are returned The matrices are ordered least-significant-bit first; in other words the first entry, with
transposed: the first index is the input bit, and the second index is index (0, 0), corresponds to the effect of the least-significant bit of the input on
the corresponding output bit. the least-significant bit of the output.
The matrices are used to select which bits are XORd together to compute For convenience of implementation, both matrices are returned transposed: the first index
each bit i of the new state: if F[j][i] is set then bit j of the old is the input bit, and the second index is the corresponding output bit.
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``, The matrices are used to select which bits are XORd together to compute each bit i of
``reflect_output``, or ``xor_output``. 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 :py:`initial_crc`, :py:`reflect_input`,
:py:`reflect_output`, or :py:`xor_output`.
""" """
f = [] f = []
g = [] g = []
algo = self.algorithm algo = self.algorithm
algo.reflect_input = algo.reflect_output = False algo.reflect_input = algo.reflect_output = False
algo.xor_output = 0 algo.xor_output = 0
crc = Parameters(algo, self._data_width) crc = Parameters(algo, self.data_width)
for i in range(self._crc_width): for i in range(self._crc_width):
crc._initial_crc = 2 ** i crc._initial_crc = 2 ** i
w = crc.compute([0]) w = crc.compute([0])
f.append([int(x) for x in reversed(f"{w:0{self._crc_width}b}")]) f.append([int(x) for x in reversed(f"{w:0{self._crc_width}b}")])
for i in range(self._data_width): for i in range(self.data_width):
crc._initial_crc = 0 crc._initial_crc = 0
w = crc.compute([2 ** i]) w = crc.compute([2 ** i])
g.append([int(x) for x in reversed(f"{w:0{self._crc_width}b}")]) g.append([int(x) for x in reversed(f"{w:0{self._crc_width}b}")])
return f, g return f, g
def __repr__(self): def __repr__(self):
return f"Parameters({self.algorithm!r}, data_width={self._data_width})" return f"Parameters({self.algorithm!r}, data_width={self.data_width})"
class Processor(Elaboratable): class Processor(Elaboratable):
""" """Hardware cyclic redundancy check generator.
Cyclic redundancy check (CRC) processor module.
This module generates CRCs from an input data stream, which can be used This module generates CRCs from an input data stream, which can be used to validate an existing
to validate an existing CRC or generate a new CRC. It is configured by CRC or generate a new CRC. It is configured by the :class:`Parameters` class, which can handle
the :py:class:`Parameters` class, which can handle most forms of CRCs. most types 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, The CRC value is updated on any clock cycle where :py:`valid` is asserted, with the updated
with the updated value available on the ``crc`` output on the subsequent value available on the :py:`crc` output on the subsequent clock cycle. The latency is therefore
clock cycle. The latency is therefore one clock cycle, and the throughput one clock cycle, and the throughput is one data word per clock cycle.
is one data word per clock cycle.
The CRC is reset to its initial value whenever ``start`` is asserted. The CRC is reset to its initial value whenever :py:`start` is asserted. :py:`start` and
``start`` and ``valid`` may be asserted on the same clock cycle, in which :py:`valid` may be asserted on the same clock cycle, in which case a new CRC computation is
case a new CRC computation is started with the current value of ``data``. started with the current value of `data`.
With ``data_width=1``, a classic bit-serial CRC is implemented for the When :py:`data_width` is 1, a classic bit-serial CRC is implemented for the given polynomial
given polynomial in a Galois-type shift register. For larger values of in a Galois-type shift register. For larger values of :py:`data_width`, a similar architecture
``data_width``, a similar architecture computes every new bit of the computes every new bit of the CRC in parallel.
CRC in parallel.
The ``match_detected`` output may be used to validate data with a trailing The :py:`match_detected` output may be used to validate data with a trailing CRC (also known as
CRC (also known as a codeword). If the most recently processed word(s) form a codeword). If the most recently processed data word(s) form the valid CRC of all the previous
the valid CRC of all the previous data since ``start`` was asserted, the data words since :py:`start` was asserted, the CRC register will always take on a fixed value
CRC register will always take on a fixed value known as the residue. The known as the :meth:`residue <Parameters.residue>`. The :py:`match_detected` output indicates
``match_detected`` output indicates whether the CRC register currently whether the CRC register currently contains this residue.
contains this residue.
Parameters Parameters
---------- ----------
parameters : Parameters parameters : :class:`Parameters`
CRC parameters. Parameters used for computation.
Attributes Attributes
---------- ----------
start : Signal(), in start : Signal(), in
Assert to indicate the start of a CRC computation, re-initialising Assert to indicate the start of a CRC computation, re-initialising the CRC register to
the CRC register to the initial value. May be asserted simultaneously the initial value. May be asserted simultaneously with :py:`valid` or by itself.
with ``valid`` or by itself.
data : Signal(data_width), in data : Signal(data_width), in
Data word to add to CRC when ``valid`` is asserted. Data word to add to CRC when :py:`valid` is asserted.
valid : Signal(), in valid : Signal(), in
Assert when ``data`` is valid to add the data word to the CRC. Assert when :py:`data` is valid to add the data word to the CRC.
crc : Signal(crc_width), out crc : Signal(crc_width), out
Registered CRC output value, updated one clock cycle after ``valid`` Registered CRC output value, updated one clock cycle after :py:`valid` becomes asserted.
becomes asserted.
match_detected : Signal(), out match_detected : Signal(), out
Asserted if the current CRC value indicates a valid codeword has been Asserted if the current CRC value indicates a valid codeword has been received.
received.
""" """
def __init__(self, parameters): def __init__(self, parameters):
if not isinstance(parameters, Parameters): if not isinstance(parameters, Parameters):
raise TypeError("Algorithmn parameters must be of type Parameters, " raise TypeError("Algorithm parameters must be of a Parameters instance, "
"not {!r}" "not {!r}"
.format(parameters)) .format(parameters))
self._crc_width = parameters._crc_width self._crc_width = parameters._crc_width
self._data_width = parameters._data_width self._data_width = parameters.data_width
self._polynomial = parameters._polynomial self._polynomial = parameters._polynomial
self._initial_crc = Const(parameters._initial_crc, self._crc_width) self._initial_crc = Const(parameters._initial_crc, self._crc_width)
self._reflect_input = parameters._reflect_input self._reflect_input = parameters._reflect_input

View file

@ -1,17 +1,10 @@
""" """
This module contains a catalog of predefined CRC algorithms. This module contains a catalog of predefined CRC algorithms, retrieved from the `reveng catalogue`_
on 2023-05-25.
All entries are from `reveng`_, accessed on 2023-05-25. .. _reveng catalogue: https://reveng.sourceforge.io/crc-catalogue/all.htm
.. _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()
See the documentation for the :mod:`~amaranth.lib.crc` module for examples.
""" """
from . import Algorithm from . import Algorithm

View file

@ -1,10 +1,74 @@
Cyclic redundancy checks Cyclic redundancy checks
######################## ########################
.. automodule:: amaranth.lib.crc .. py:module:: amaranth.lib.crc
The :mod:`amaranth.lib.crc` module provides facilities for computing cyclic redundancy checks (CRCs)
in software and in hardware.
Introduction
============
The essentials of a CRC computation are specified with an :class:`Algorithm` object, which defines
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 an :class:`Algorithm`.
An :class:`Algorithm` is specialized for a particular data width to obtain :class:`Parameters`,
which fully define a CRC computation. :meth:`Parameters.compute` computes a CRC in software, while
:meth:`Parameters.create` creates a :class:`Processor` that computes a CRC in hardware.
Examples
========
.. testsetup::
from amaranth import *
m = Module()
.. testcode::
from amaranth.lib.crc import Algorithm
from amaranth.lib.crc.catalog import CRC16_CCITT, CRC16_USB
# Compute a CRC in hardware using the predefined CRC16-CCITT algorithm and the data word
# width of 8 bits (in other words, computing it over bytes).
m.submodules.crc16_ccitt = crc16_ccitt = CRC16_CCITT().create()
# Compute a CRC in hardware using the predefined CRC16-USB algorithm and the data word
# width of 32 bits.
m.submodules.crc16_usb = crc16_usb = CRC16_USB(32).create()
# Compute a CRC in software using a custom CRC algorithm and explicitly specified data word
# width.
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
Algorithms and parameters
=========================
.. autoclass:: Algorithm
:special-members: __call__ :special-members: __call__
The following pre-defined CRC algorithms are available: .. autoclass:: Parameters
CRC computation
===============
.. autoclass:: Processor()
Predefined algorithms
=====================
The following predefined CRC algorithms are available:
.. toctree:: .. toctree::

View file

@ -1,4 +1,4 @@
Predefined CRC Algorithms Algorithm catalog
######################### #################
.. automodule:: amaranth.lib.crc.catalog .. automodule:: amaranth.lib.crc.catalog