汇编AVR ATMEGA128:CRC算法

Assembly AVR ATMEGA128: CRC Algorithm

我必须对以下内容进行简单的 CRC 检查:从端口获取一个 8 位输入,获取它的 CRC 校验和值并将其输出。到目前为止,我可以获取输入并读取算法,因此我将 n - 1 个零添加到我的输入中,有效地使其足够大到 16 位。我也得到了它的工作,我知道我在这里需要一个异或,因为我们在除法时做一个模 2。但是,我无法进一步研究该算法,甚至不知道从哪里开始。

.MACRO INITSTACK
LDI         R16,        HIGH(RAMEND)
OUT         SPH,        R16
LDI         R16,        LOW(RAMEND)
OUT         SPL,        R16
.ENDMACRO

.MACRO LOADIO
LDI         R20,        @1
OUT         @0,         R20
.ENDMACRO

.include    "m128def.inc"
.EQU        ones = 0xFF             ; output
.EQU        zeros = 0x00            ; input
.EQU        CRC_CODE = 0x13         ; our CRC polynomial in binary (10011)
.DEF        INPUTREG = R16          ; input register
.DEF        CRC_RES = R17           ; Holds the CRC result (4 bits)
.DEF        OPREG1 = R18            ; temp operation register 1
.DEF        OPREG2 = R19            ; temp operation register 2
.DEF        OPREG3 = R20            ; temp operation register 3
.DEF        OPREG4 = R21            ; temp operation register 4
.DEF        OPREG5 = R22            ; temp operation register 5
.ORG        0x0000

main:

INITSTACK

; Modifies the INPUTREG
RCALL       TakeInput
RCALL       CreateCRC

LOADIO      DDRA,           ones
LOADIO      DDRB,           ones
OUT         PORTA,          CRC_RES

Stop:
NOP
JMP         Stop


TakeInput:
    LOADIO      DDRA,       zeros
    IN          INPUTREG,   PORTA
    CLR         XH
    MOV         XL,         INPUTREG
    LSL         XL          ; do a shift 4 times, for the 4 (5 - 1) zeros
    ROL         XH
    LSL         XL          ; do a shift 4 times, for the 4 (5 - 1) zeros
    ROL         XH
    LSL         XL          ; do a shift 4 times, for the 4 (5 - 1) zeros
    ROL         XH
    LSL         XL          ; do a shift 4 times, for the 4 (5 - 1) zeros
    ROL         XH
    RET

CreateCRC:
    LDI         OPREG1,     0x08        ; do shift 8 times
    LDI         OPREG2,     CRC_CODE    ; load the polynom
    LSL         OPREG2                  ; no need for 5th bit, we only do operation with lower 4 bits (CLC does XOR for the high bit we skipped)
    SWAP        OPREG2                  ; Swap nibbles, so the number has the bits we want at higher 4 bits
    CLZ
crc_loop:
    CLC
    ROL         INPUTREG
    DEC         OPREG1
    BREQ        crc_end                 ; if we did this 8 times, stop
    BRCC        crc_loop                ; no carry, then keep shifting, if its set we go to XOR
crc_do_xor:
    EOR         INPUTREG,   OPREG2
    JMP         crc_loop
crc_end:
    SWAP        INPUTREG                ; Swap the higher 4 bits to lower 4 bits
    MOV         CRC_RES,    INPUTREG
    RET

编辑:现在我得到的消息 1100 1111 的结果不正确,代码为 10011。输出应该是 1100,但我得到的是 1101。哪里错了?

您的代码似乎还没有任何用处。您需要考虑算法的工作原理,并决定使用所需字节的好方法。

由于您的输入只是一个字节而不是一个流,我建议您使用该字节并执行 8 次移位。我建议你使用 ROL,通过进位向左循环,和 CLC,清除进位,以及 XOR 指令。

思路是清除进位标志,然后向左循环一个位置。如果设置了进位,则需要与00110000进行异或指令。这是没有第一个1的多项式,向左移动。

1) 11001111 CLC and ROL
2) 10011110 with C=1, so do an XOR
   10101110 CLC and ROL
3) 01011100 with C=1, so do an XOR
   01101100 CLC and ROL
4) 11011000 with C=0, so don't XOR. 
            CLC and ROL
5) 10110000 with C=1, so do an XOR
   01000000 CLC and ROL
6) 10000000 with C=0, so don't XOR.
            CLC and ROL
7) 00000000 with C=1, so do an XOR
   00110000 CLC and ROL
8) 01100000 with C=0, so don't XOR. 
            CLC and ROL
9) 11000000 The first four bits are the result. SWAP to get it to the right.

编写执行该算法的循环,测试 C 位的分支。请注意,不需要直接使用多项式的高位。这意味着,如果设置了进位,您只能对低位进行 XOR。 CLC 为进位位本身执行 "XOR"。