我正在尝试编写一个基于表的CRC例程来接收模式S上行链路询问器消息。在下行链路侧,CRC仅是基于多项式P = 0x1FFF409的24位CRC。到目前为止,非常好 - 我写了一个基于表的实现,遵循通常的一次一个字符的惯例,并且它工作正常。
然而,在上行链路方面,事情变得奇怪了。 protocol specification表示计算目标上行链路地址是通过查找:
U'= x ^ 24 * U / G(x)
...其中U是收到的消息,G(x)是编码多项式0x1FFF409,导致:
U'= x ^ 24 * m(x)+ A(x)+ r(x)/ G(x)
...其中m(x)是原始消息,A(x)是地址,r(x)是余数。我想要低阶商A(x);例如,GF(2)多项式除法运算的结果而不是余数。其余部分被有效地丢弃。目标地址使用传输的校验和进行编码,以便接收飞机可以通过将校验和与其地址进行比较来验证校验和。
这很棒,而且我从上面得到了一个按位实现。请忽略多项式和校验和的奇怪移位,这已经从假设32位寄存器的this Pascal implementation(第15页)中得到了证实,并根据该假设进行了优化。实际上,消息和校验和是单个56位传输。
#This is the reference bit-shifting implementation. It is slow.
def uplink_bitshift_crc():
p = 0xfffa0480 #polynomial (0x1FFF409 shifted left 7 bits)
a = 0x00000000 #rx'ed uplink data (32 bits)
adr = 0xcc5ee900 #rx'ed checksum (24 bits, shifted left 8 bits)
ad = 0 #will hold division result low-order bits
for j in range(56):
#if MSBit is 1, xor w/poly
if a & 0x80000000:
a = a ^ p
#shift off the top bit of A (we're done with it),
#and shift in the top bit of adr
a = ((a << 1) & 0xFFFFFFFF) + ((adr >> 31) & 1)
#shift off the top bit of adr
adr = (adr << 1) & 0xFFFFFFFF
if j > 30:
#shift ad left 1 bit and shift in the msbit of a
#this extracts the LS 24bits of the division operation
#and ignores the remainder at the end
ad = ad + ((a >> 31) & 1)
ad = ((ad << 1) & 0xFFFFFFFF)
#correct the ad
ad = ad >> 2
return ad
以上当然比软件中的糖蜜慢,我真的希望能够构建一个查找表,允许对接收到的地址进行类似的一次一字节计算,或者按下其余部分(很快被计算成一个商。
TL; DR : 给定一个消息,编码多项式和余数(通过常规CRC方法计算),有一种更快的方法来获得多项式除法运算的商,而不是使用移位寄存器进行多项式除法“普通写法”?
答案 0 :(得分:0)
您可以查看PyCRC library,我想这可能会回答您的问题。
答案 1 :(得分:0)
对于OP来说为时已晚,但是我将其发布给其他可能会看到此问题的人。您可以生成两个表来一次操作一个字节。前256 x 8位表由当前除数(消息)的前8位索引,并且8位值是商。第二个256 x 32位表由8位商索引,而32位值是8位商乘25位多项式的32位乘积(由于这是无进位乘法,乘积为32位(x ^ 7 * x ^ 24 = x ^ 31)),您可以对被除数的高32位进行异或,以将被除数的高8位清零。然后循环返回下一个8位分红。
现代的X86 CPU具有无进位乘法指令PCLMULQDQ,该指令在128位xmm寄存器上运行,执行64位乘64位乘法以产生128位乘积(因为它是无进位乘法位127始终为0,所以它是确实是127位产品)。将56位消息乘以41位常量2 ^ 64 / G(x)将得到96位乘积,其中高32位将为商(不使用低64位)。