Source code for hwtLib.logic.crc_test_utils
from typing import Optional
from hwtLib.logic.crcPoly import CRC_POLY
from pyMathBitPrecise.bit_utils import reverse_bits, mask, \
bit_list_reversed_endianity, bit_list_reversed_bits_in_bytes, \
bit_list_to_int
from hwtLib.logic.crcComb import CrcComb
[docs]class NaiveCrcAccumulator:
"""
Holds the intermediate state of the CRC algorithm.
Based on http://www.nightmare.com/~ryb/
"""
[docs] def __init__(self, params: CRC_POLY, value: Optional[int]=None):
"""
:param value:
The initial register value to use. The result previous of a
previous CRC calculation, can be used here to continue
calculation with more data. If this parameter is ``None``
or not given, the register will be initialized with
algorithm's default seed value.
"""
self.params = params
self.bitMask = mask(params.WIDTH)
self.polyMask = params.POLY & self.bitMask
self.inBitMask = 1
self.outBitMask = 1 << (params.WIDTH - 1)
if params.REFIN:
self.polyMask = reverse_bits(self.polyMask, params.WIDTH)
# (swap)
self.inBitMask = self.outBitMask
self.outBitMask = 1
# print("%x" % self.polyMask, self.inBitMask, self.outBitMask)
self.REFOUT = params.REFOUT
self.reset()
if value is not None:
self.value = value ^ params.XOROUT
[docs] def reset(self):
"""
Reset the state of the register with the default seed value.
"""
self.value = self.params.INIT
[docs] def takeBit(self, bit: int):
"""
Process a single input bit.
"""
assert bit in (0, 1, True, False), bit
outBit = int((self.value & self.outBitMask) != 0)
if self.params.REFIN:
self.value >>= 1
else:
self.value <<= 1
self.value &= self.bitMask
# print("o, i", outBit, bit)
if outBit ^ bit:
self.value ^= self.polyMask
# print("{0:05b}".format(self.value))
[docs] def takeWord(self, word: int, width: int):
"""
Process a binary input word.
:param word:
The input word. Since this can be a Python ``long``, there
is no coded limit to the number of bits the word can
represent.
"""
assert (word >> width) == 0, (word, width)
if self.REFOUT:
bitI = range(0, width)
else:
bitI = range(width - 1, -1, -1)
# sprint(self.value)
for i in bitI:
self.takeBit((word >> i) & 1)
[docs] def getValue(self):
"""
Return the current value of the register as an integer.
"""
return self.value
[docs] def getFinalValue(self):
"""
Return the current value of the register as an integer with
*xorMask* applied. This can be used after all input data is
processed to obtain the final result.
"""
v = self.value ^ self.params.XOROUT
if self.REFOUT:
v = reverse_bits(v, self.params.WIDTH)
return v
[docs]def naive_crc(dataBits, crcBits, polyBits,
refin=False, refout=False):
crc_mask = CrcComb.buildCrcXorMatrix(len(dataBits), polyBits)
dataBits = bit_list_reversed_endianity(dataBits)
if refin:
# reflect bytes in input data signal
# whole signal should not be reflected if DW > PW
# polyBits = list(reversed(polyBits))
dataBits = bit_list_reversed_bits_in_bytes(dataBits)
# crcBits = reversedBitsInBytes(crcBits)
res = []
for stateMask, dataMask in crc_mask:
# if refin:
# stateMask = reversed(stateMask)
# dataMask = reversed(dataMask)
v = 0
for useBit, b in zip(stateMask, crcBits):
if useBit:
v ^= b
for useBit, b in zip(dataMask, dataBits):
if useBit:
v ^= b
res.append(v)
assert len(res) == len(polyBits)
if refout:
res = reversed(res)
return bit_list_to_int(res)
if __name__ == "__main__":
from hwtLib.logic.crcPoly import CRC_5_USB
def assert_eq(r, v):
if r.getFinalValue() == v:
print("OK: {0:05b}".format(v))
return
else:
print(r)
print("Error: {0:05b} != {1:05b}".format(
r.getFinalValue(), v))
# from https://www.usb.org/sites/default/files/crcdes.pdf
r = NaiveCrcAccumulator(CRC_5_USB)
r.takeWord(0x0710, 11)
assert_eq(r, 0b10100)
r = NaiveCrcAccumulator(CRC_5_USB)
r.takeWord(0x15, 7)
r.takeWord(0xE, 4)
assert_eq(r, 0b10111)