Sie sind auf Seite 1von 7

29/6/2014 www.dattalo.com/technical/software/pic/crc16.

asm
http://www.dattalo.com/technical/software/pic/crc16.asm 1/7
list p=p16f84
#include p16f84.inc
cblock 0x0c
;Variables for the optimized CRC16 computation
crcHi
crcLo
index
temp
;Variables for the looped CRC16 computation
wCrc:2
bLoop
bNewByte
;Variables for running a comparison between the
;two algorithms.
test_byte
test_crcHi
test_crcLo
endc
org 0
goto main
;========================================================================
; CRC-16
;
; References:
; http://www.repairfaq.org/filipg/LINK/F_crc_v3.html
; http://www.netrino.com/Connecting/2000-01/
;
; According to the above references, the CRC-16 algorithm is the reversed
; CRC algorithm for the polynomial 0x8005. To be complete, the parameters
; for the CRC-16 algorithm are:
;
; Width: 16 bits
; Polynomial: 0x8005
; Initial: 0x0000
; Xor out: 0x0000
; Reflected data: yes
; Reflected remainder: yes
;
; The 'reflected' refers to a detail in the implementation of the algorithm
; (which is described in the above references). The simple (i.e. easy to
; understand, but slow) algorithm reverses the bit pattern of the polynomial
; for the reversed CRC algorithms. This simple algorithm can be shown to be
; implemented by:
;
; wCrc ^= bNewByte;
;
; bLoop = 8;
; do
; {
; if(wCrc & 1) {
; wCrc >>= 1;
29/6/2014 www.dattalo.com/technical/software/pic/crc16.asm
http://www.dattalo.com/technical/software/pic/crc16.asm 2/7
; wCrc ^= 0xA001;
; } else
; wCrc >>= 1;
;
; } while (--bLoop);
;
; The 8005 polynomial is reversed and becomes A001.
;
; This simple algorithm takes a byte as its input and operates on each bit
; in succession. It's possible to compute this loop much more efficiently.
; Most (all?) implementations I've seen use look up tables to speed things
; up. However, it's possible to speed up the computation using boolean
; arithmetic too. And on a PIC processor where look up tables are relatively
; expensive, the boolean arithmetic approach is both faster and takes less
; program memory.
;
; Given: Assume the looped implementation shown above is correct.
;
; How can boolean equations be written to generate the same result?
;
; It helps to describe the algorithm. To compute the CRC for the next byte
; of a message, we first start off by xor'ing it with the current CRC value.
; We then loop 8 times and at each iteration, we examine the current CRC
; value. If its least significant bit is set, then we shift the CRC right 1
; bit position and xor it with the reversed polynomial A001. If the least
; significant bit is not set, then we simply shift the CRC right 1 position
; but don't xor it with anything.
;
; It's convenient to unroll the loop and express the bit manipulation
; operations using a table:
;
;
; Input byte --> n7 n6 n5 n4 n3 n2 n1 n0
; Initial CRC --> wf we wd wc wb wa w9 w8 w7 w6 w5 w4 w3 w2 w1 w0
; --------------------------------------------------
; a0 0 a0 0 0 0 0 0 0 0 0 0 0 0 0 a0
; a1 0 a1 0 0 0 0 0 0 0 0 0 0 0 0 a1
; a2 0 a2 0 0 0 0 0 0 0 0 0 0 0 0 a2
; a3 0 a3 0 0 0 0 0 0 0 0 0 0 0 0 a3
; a4 0 a4 0 0 0 0 0 0 0 0 0 0 0 0 a4
; a5 0 a5 0 0 0 0 0 0 0 0 0 0 0 0 a5
; a6 0 a6 0 0 0 0 0 0 0 0 0 0 0 0 a6
; a7 0 a7 0 0 0 0 0 0 0 0 0 0 0 0 a7
; --------------------------------------------------
; wf we wd wc wb wa w9 w8 w7 w6 w5 w4 w3 w2 w1 w0 <-- Final CRC
;
; In this table, each column corresponds to a bit position. The 8-bit input is
; shown at the top as bits n7 through n0. The Initial CRC is shown at the top
; as bits wf through w0. The next 8 rows are the polynomial. The bit pattern
; for A001 is 1010 0000 0000 0001 and you can see how the a_i's align with
; this pattern. The reason for the a_i's is that it provides a symbolic way
; to express whether the polynomial will be XOR'd or not at each iteration.
; In other words, if the poylnomial is not XOR'd then the a_i's will be zero
; (xor'ing with a 0 is a no-operation). If the polynomial is xor'd then the
; a_i's will be a 1.
;
; Finally, the last row in the table is the resulting CRC. The way the table
; works is that each bit in the final CRC is result of XOR'ing all of the bits
; in the bit column. For example, the final w0 bit is a7^w8. All 16-bits of
; the final equation are:
;
29/6/2014 www.dattalo.com/technical/software/pic/crc16.asm
http://www.dattalo.com/technical/software/pic/crc16.asm 3/7
; w0 = w8' ^ a7 w8 = a0 ^ a2
; w1 = w9' w9 = a1 ^ a3
; w2 = wa' wa = a2 ^ a4
; w3 = wb' wb = a3 ^ a5
; w4 = wc' wc = a4 ^ a6
; w5 = wd' wd = a5 ^ a7
; w6 = we' ^ a0 we = a6
; w7 = wf' ^ a1 wf = a7
;
; The next step is to determine the values for a_i. Each a_i is equal to the
; LSB of the CRC value from the previous iteration of the loop. For example,
; when the loop first begins, the lsb of the CRC is n0 ^ w0. Thus a0 = n0^w0.
; If n0^w0 is a binary 1, then the bit pattern 1010 0000 0000 0001 will be
; XOR'd with the shifted CRC. This means for the next iteration the LSB of
; the CRC will depend on w1^n1 and it will depend on a0. Specifically,
; a1 = n1^w1^a0. This can be read off the table by examining the bit column
; just to the right of the a1 (i.e. the column with n1). Here are all of the
; equations
;
; a0 = n0^w0
; a1 = n1^w1^a0
; a2 = n2^w2^a1
; a3 = n3^w3^a2
; a4 = n4^w4^a3
; a5 = n5^w5^a4
; a6 = n6^w6^a5
; a7 = n7^w7^a6
;
; And to simplify things just a bit, let all of n^w combinations be call 'i'.
;
; a0 = i0
; a1 = i1^a0
; a2 = i2^a1
; a3 = i3^a2
; a4 = i4^a3
; a5 = i5^a4
; a6 = i6^a5
; a7 = i7^a6
;
; These 8 equations for the a's can be solved in terms of the i's:
;
; a0 = i0
; a1 = i1^i0
; a2 = i2^i1^i0
; a3 = i3^i2^i1^i0
; a4 = i4^i3^i2^i1^i0
; a5 = i5^i4^i3^i2^i1^i0
; a6 = i6^i5^i4^i3^i2^i1^i0
; a7 = i7^i6^i5^i4^i3^i2^i1^i0
;
; And finally, these expressions for the a's can be substituted into
; the equations for the final CRC:
;
; w0 = w8' ^ i7^i6^i5^i4^i3^i2^i1^i0 w8 = i1 ^ i2
; w1 = w9' w9 = i2 ^ i3
; w2 = wa' wa = i3 ^ i4
; w3 = wb' wb = i4 ^ i5
; w4 = wc' wc = i5 ^ i6
; w5 = wd' wd = i6 ^ i7
; w6 = we' ^ i0 we = i6^i5^i4^i3^i2^i1^i0
; w7 = wf' ^ i0 ^ i1 wf = i7^i6^i5^i4^i3^i2^i1^i0
29/6/2014 www.dattalo.com/technical/software/pic/crc16.asm
http://www.dattalo.com/technical/software/pic/crc16.asm 4/7
;
; That completes the derivation or the boolean equations. Next, let's derive
; a C program that implements these:
;
;
; unsigned int i;
; unsigned int p;
;
; i = (wCrc ^ bNewByte) & 0xff;
;
; /* Compute the parity of i: */
; p = i ^ (i>>4);
; p = p ^ (p>>2);
; p = p ^ (p>>1) & 1;
;
; p = p ? 0xc001 : 0x0000;
;
; wCrc = (wCrc>>8) ^ p ^ (i<<6) ^ (i<<7);
;
;
; Input: W = new 8-bit byte
; crcLo:crcHi - current 16-bit CRC
;
; Output:
; crcLo:crcHi - updated 16-bit CRC
;
; Memory used:
; index
; temp
;
; Cycles:
; 23 (excluding return)
CRC16:
XORWF crcLo,W
MOVWF index
MOVF crcHi,W
MOVWF crcLo ;crcLo = crc >> 8
CLRF temp ;Holds the CRC pattern for the low byte
CLRC ;
RRF index,W ;W = 0.i7.i6.i5.i4.i3.i2.i1 C=i0
XORWF index,F ;F = 0i7.i7i6.i6i5.i5i4.i4i3.i3i2.i2i1.i1i0
RRF temp,F ;t = i0.0.0.0.0.0.0.0 C=0

RRF index,W ;W = 0.0i7.i7i6.i6i5.i5i4.i4i3.i3i2.i2i1 C=i1i0
MOVWF crcHi ;crcHi = 0.0i7.i7i6.i6i5.i5i4.i4i3.i3i2.i2i1
RRF temp,F ;t = i1i0.i0.0.0.0.0.0.0 C=0
RLF index,F ;W = i7i6.i6i5.i5i4.i4i3.i3i2.i2i1.i1i0.0 C=i7
XORWF index,F ;F = X.X.i7i6i5i4.X.X.X.i3i2i1i0.X

SWAPF index,W ;F = X.X.i3i2i1i0.X.X.X.i7i6i5i4.X
XORWF index,F ;F = X.X.P.X.X.X.P.X where P= parity(index)
; at this point, the parity of the index byte is now at bits 1 and 5 of index.
MOVF temp,W ;W = i1i0.i0.0.0.0.0.0.0
BTFSC index,1 ;If P==1
XORLW 1 ;W = i1i0.i0.0.0.0.0.0.P
29/6/2014 www.dattalo.com/technical/software/pic/crc16.asm
http://www.dattalo.com/technical/software/pic/crc16.asm 5/7
XORWF crcLo,F ;crcLo = (crc>>8) ^ i1i0.i0.0.0.0.0.0.P
MOVLW 0xC0
BTFSC index,1
XORWF crcHi,F ;crcHi = P.Pi7.i7i6.i6i5.i5i4.i4i3.i3i2.i2i1
return
;------------------------------------------------------------------------
;
; vUpdateCrc - looped implementation of the CRC-16 algorithm
;
; Written by Johan Bodin.
;
;void vUpdateCrc (char bNewByte)
;{
CRC16_looped
MOVWF bNewByte
; char bLoop;
;
; wCrc.low8 ^= bNewByte;
XORWF wCrc,F
;
; bLoop = 8;
MOVLW .8
MOVWF bLoop
; do
; {
; Carry = 0;
m001 CLRC
; rr (wCrc.high8);
RRF wCrc+1,F
; rr (wCrc.low8);
RRF wCrc,F
; if (Carry)
SKPC
GOTO m002
; wCrc ^= 0xA001;
MOVLW .160
XORWF wCrc+1,F
MOVLW .1
XORWF wCrc,F
; } while (--bLoop);
m002 DECFSZ bLoop,F
GOTO m001
;}
RETURN

;========================================================================
initCrc:
MOVF test_crcLo,W
MOVWF crcLo
MOVWF wCrc
MOVF test_crcHi,W
MOVWF crcHi
MOVWF wCrc+1
return

29/6/2014 www.dattalo.com/technical/software/pic/crc16.asm
http://www.dattalo.com/technical/software/pic/crc16.asm 6/7
main:
clrf crcLo
clrf crcHi
movlw '1'
call CRC16
movlw '2'
call CRC16
movlw '3'
call CRC16
movlw '4'
call CRC16
movlw '5'
call CRC16
movlw '6'
call CRC16
movlw '7'
call CRC16
movlw '8'
call CRC16
movlw '9'
call CRC16
; crc should be 0xBB3D
clrf test_byte
clrf test_crcLo
clrf test_crcHi
loop:
call initCrc
movf test_byte,W
call CRC16

movf test_byte,W
call CRC16_looped
; compare
movf crcLo,W
xorwf wCrc,W
skpz
goto failed

movf crcHi,W
xorwf wCrc+1,W
skpz
goto failed
decfsz test_byte,F
goto loop
clrwdt
decfsz test_crcLo,F
29/6/2014 www.dattalo.com/technical/software/pic/crc16.asm
http://www.dattalo.com/technical/software/pic/crc16.asm 7/7
goto loop

decfsz test_crcHi,F
goto loop
passed: goto passed
failed: goto failed
end

Das könnte Ihnen auch gefallen