Assembly AVR ATMEGA128: CRC Algorithm

时间:2016-04-12 00:42:00

标签: assembly avr crc atmega

I have to do a simple CRC check for the following: Take an 8-bit input from a port, get it's CRC checksum value and output it. So far, I can take the input and I read the algorithm, so I append n - 1 zeros to my input, effectively making it big enough to be 16 bit. I got that working as well and I know I'll need a XOR here as we do a modulo 2 while dividing. But, I can't go any further with the algorithm, don't know where to even start.

.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

EDIT: Now I get an incorrect result for the message 1100 1111 with code 10011. Output should be 1100 but I get 1101. Where could it be wrong?

1 个答案:

答案 0 :(得分:2)

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

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

想法是清除进位标志,然后向左旋转一个位置。如果进位位置1,则需要使用00110000执行XOR指令。这是没有前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位以进行分支。请注意,多项式的高位不需要直接使用。这意味着,如果进位位置1,则只对低位进行异或。 CLC对进位位本身进行“异或”。