———

# CRC (assembly and C)

## Background

PIC CRC16 (CRC-CCITT-16 0x1021)

Representations: normal / reversed / reverse of reciprocal: 0x1021 / 0x8408 / 0x8810

Ashley Roll posted some code on the piclist (http://www.piclist.com) that implemented “CRC16” - or the CRC-CCITT-16 algorithm for the polynomial 0x1021. Tony K�bek and I took a few rounds optimizing the code and we ended up with a PIC implementation that was only 17 instructions (and 17 cycles, i.e. unlooped)!

After further investigations, I found that the algorithm can be expressed:

int x;

x = ((crc»8) ^ data) & 0xff; x ^= x»4;

crc = (crc « 8) ^ (x « 12) ^ (x «5) ^ x;

crc &= 0xffff;

No claim is made here that this is the first time that this algorithm has been expressed this way. But, it's the first time I've seen like this. Using this as a guide, I wrote another routine in PIC assembly. Unfortunately, this one takes 17 cycles too.

Digital Nemesis Pty Ltd (ash at digitalnemesis.com)

Original Code: Ashley Roll

Optimisations: Scott Dattalo

## C code

```int16 crc_1021(int16 old_crc, int8 data)
{
int16 crc;
int16 x;

x = make8(old_crc,1) ^ data;  //x = ((old_crc>>8) ^ data) & 0xff;
x ^= x>>4;

crc = (old_crc << 8) ^ (x << 12) ^ (x <<5) ^ x;

crc &= 0xffff;

return crc;
}```

## Assembly code

Same algorithm but now in assembly:

```// Register defines for the PIC18F458
unsigned int16 FSR0;
#locate FSR0=0x0FE9

//-----------------------------------------------------------------------------
// Calculate the CRC16 value of a specified buffer.
//
// A very fast CRC-16 routine based on the CCITT polynome 0x1021.
// This implementation is very small and fast. Using some specific features of
// the polynome the resulting code is even faster than table driven algorithms.
//
// Original Code: Ashley Roll       www.digitalnemesis.com
// Optimisations: Scott Dattalo     www.dattalo.com
//-----------------------------------------------------------------------------
int16 Calc_Crc16(int8 *Buffer, int16 Len) // Note: save 5 instructions by
{                                         // changing 'int16 Len' to 'int8 Len'.
int8 Index;
union
{
int8  uByte;
int16 uWord;
} CRC16;

CRC16.uWord = 0xFFFF;     // Initialise CRC to 0xFFFF
FSR0 = Buffer;            // Copy Buffer address to pointer register FSR0

do
{
#ASM
movf  POSTINC0,w        // load w with next databyte
xorwf CRC16.uByte,w  // (a^x):(b^y)
movwf Index             //
andlw 0xf0              // W = (a^x):0
swapf Index,f           // Index = (b^y):(a^x)
xorwf Index,f           // Index = (a^b^x^y):(a^x) = i2:i1

// High byte
movf  Index,W
andlw 0xf0
xorwf CRC16.uByte,W
movwf CRC16.uByte

rlcf  Index,W           // use rlf for PIC16
rlcf  Index,W           // use rlf for PIC16
xorwf CRC16.uByte,f
andlw 0xe0
xorwf CRC16.uByte,f

swapf Index,F
xorwf Index,W
movwf CRC16.uByte
#ENDASM
} while (--Len);

return CRC16.uWord;
}``` 