2003-11-09 Theodore A. Roth * include/avr/crc16.h (_crc16_update): Add dox. (_crc_xmodem_update): New function. Index: include/avr/crc16.h =================================================================== RCS file: /cvsroot/avr-libc/avr-libc/include/avr/crc16.h,v retrieving revision 1.2 diff -u -r1.2 crc16.h --- include/avr/crc16.h 12 Dec 2002 11:41:01 -0000 1.2 +++ include/avr/crc16.h 10 Nov 2003 01:43:55 -0000 @@ -25,18 +25,37 @@ /* $Id: crc16.h,v 1.2 2002/12/12 11:41:01 joerg_wunsch Exp $ */ -/* - avr/crc16.h - optimized CRC-16 +#ifndef _AVR_CRC16_H_ +#define _AVR_CRC16_H_ - Polynomial: x^16 + x^15 + x^2 + 1 (0xa001) - Initial value: 0xffff +/** \defgroup avr_crc CRC Computations + \code#include \endcode - See the Dallas Semiconductor app note 27 for 8051 assembler example - and general CRC optimization suggestions. - */ + This header file provides a optimized inline functions for calculating 16 + bit cyclic redundancy checks (CRC) using common polynomials. -#ifndef _AVR_CRC16_H_ -#define _AVR_CRC16_H_ + \par References: + + \par + + See the Dallas Semiconductor app note 27 for 8051 assembler example and + general CRC optimization suggestions. The table on the last page of the + app note is the key to understanding these implementations. + + \par + + Jack Crenshaw's "Impementing CRCs" article in the January 1992 isue of \e + Embedded \e Systems \e Programming. This may be difficult to find, but it + explains CRC's in very clear and concise terms. Well worth the effort to + obtain a copy. */ + +/** \ingroup avr_crc + Optimized CRC-16 calcutation. + + Polynomial: x^16 + x^15 + x^2 + 1 (0xa001) + Initial value: 0xffff + + This CRC is normally used in disk-drive controllers. */ static inline unsigned int _crc16_update(unsigned int __crc, unsigned char __data) @@ -73,6 +92,80 @@ : "r0" ); return __ret; +} + +/** \ingroup avr_crc + Optimized CRC-XMODEM calculation. + + Polynomial: x^16 + x^12 + x^5 + 1 (0x1021) + Initial value: 0x0 + + This is the CRC used by the Xmodem-CRC protocol. + + The following is the equivalent functionality written in C. + + \code + uint16_t + crc_xmodem_update (uint16_t crc, uint8_t data) + { + int i; + + crc = crc ^ ((uint16_t)data << 8); + for (i=0; i<8; i++) + { + if (crc & 0x8000) + crc = (crc << 1) ^ 0x1021; + else + crc <<= 1; + } + + return crc; + } + \endcode */ + +static inline unsigned int +_crc_xmodem_update(unsigned int __crc, unsigned char __data) +{ + unsigned int __ret; /* %B0:%A0 (alias for __crc) */ + unsigned char __tmp1; /* %1 */ + unsigned char __tmp2; /* %2 */ + /* %3 __data */ + + __asm__ ( + "eor %B0,%3" "\n\t" /* crc.hi ^ data */ + "mov __tmp_reg__,%B0" "\n\t" + "swap __tmp_reg__" "\n\t" /* swap(crc.hi ^ data) */ + + /* Calculate the ret.lo of the CRC. */ + "mov %1,__tmp_reg__" "\n\t" + "andi %1,0x0f" "\n\t" + "eor %1,%B0" "\n\t" + "mov %2,%B0" "\n\t" + "eor %2,__tmp_reg__" "\n\t" + "lsl %2" "\n\t" + "andi %2,0xe0" "\n\t" + "eor %1,%2" "\n\t" /* __tmp1 is now ret.lo. */ + + /* Calculate the ret.hi of the CRC. */ + "mov %2,__tmp_reg__" "\n\t" + "eor %2,%B0" "\n\t" + "andi %2,0xf0" "\n\t" + "lsr %2" "\n\t" + "mov __tmp_reg__,%B0" "\n\t" + "lsl __tmp_reg__" "\n\t" + "rol %2" "\n\t" + "lsr %B0" "\n\t" + "lsr %B0" "\n\t" + "lsr %B0" "\n\t" + "andi %B0,0x1f" "\n\t" + "eor %B0,%2" "\n\t" + "eor %B0,%A0" "\n\t" /* ret.hi is now ready. */ + "mov %A0,%1" "\n\t" /* ret.lo is now ready. */ + : "=d" (__ret), "=d" (__tmp1), "=d" (__tmp2) + : "r" (__data), "0" (__crc) + : "r0" + ); + return __ret; } #endif /* _AVR_CRC16_H_ */