[net.sources] CRC-16 algorithms from Jun 83 IEEE Micro, C & 8086 Assembler

bb@lanl-a.UUCP (11/18/83)

==============================================================================


     The following are translations of byte-wise CRC-16 calculation
     algorithms given the the June 83 issue of IEEE Micro.  Included
     are an on-the-fly 8086 assembler version, a C table driven version
     and a C program to produce the table as well as the table itself.
     I have tested these against each other and am fairly certain they
     work.  If they don't, I apologize now -- please send me your fixes.

;===================================================================
;
; CRC -- calculates CRC checksum on string of bytes
;  on the stack -- length of string, string offset
;  returns -- 16 bit CRC-16 value in AX, BX.
;             other data regs. garbled NOTE IF CI CHANGES C COMPILER
;
; Programmer: Bryan Bingham	8 Nov 1983
; System: CompuPro 8086/8085
;
; This code is intended to be called by a C program compiled with the CI-86
; compiler, the format of the directives is suggested by CI cvtobj document.
; It has no seperate data segment, it uses just registers.  The algorithm
; comes from "Byte-wise CRC Calculations" by Aram Perez, IEEE Micro June
; 1983 pp.40-50 and uses several tricks based on the 8080/8086 design.
; I suggest getting that paper if you want to understand what is happening
; because I did not try to fully document the thing here, and the comments
; here only make sense after you read the paper.
;
; Called from C as crc(buf, strlen(buf));
;===================================================================
; 
; 
	cseg
crc:             	; global entry point
; 
;	1st get params, initialize regs
;
	push 	bp		; save frame pointer
	mov	bp,sp		; get ready to read args
	mov	cx,6[bp]	; char count
	mov 	si,4[bp]	; pointer to string of bytes
	xor 	ax,ax		; 0 out accumulator, crc
	xor 	bx,bx		;
	xor	dx,dx		; used for inter. processing

;
;	Main loop, get char from string, do crc calculation
;
   	
cycle	equ	$
      	lods 	al
	xor 	al,bl		; xor low order byte of current crc
	mov	dl,al		; save for later
	add	al,al		; set cf, pf for later
	pushf			; save x8 and xx7 (cf and pf)
	xor	al,dl		; a = x.xor.(x.shl.1) r14 thru r7
	mov	dl,al		; save again
	popf			; restore flags
	mov 	al,0		; xx7 <- 0 xx8 <- xx7
	jp 	f1		; 
	mov 	al, 011b        ; if xx7  then make xx8 = 1 too
;
f1:	jnb	f2               
	xor 	al, 010b	; if x8 then complement xx8

f2:	mov	dh,al
	shr	al,1		; shift al right 1 bit
	push	cx		; save char count
	mov 	cx,6		; shift count
	shl	dx,cl
	pop	cx		; restore cx
	or      al,dl		; get last bits into proper place
	xor 	al,bh		; xor with high order CRC bits
	mov	bl,al		; save new CRC
	mov	bh,dh
	loop	cycle		; end of loop jmp back if cx <> 0
;	          
	mov	ax,bx		; put answer in ax
	pop	bp		; restore frame pointer
	ret
;
;
	eseg
;  This is for relocation -- can be left out if not using CI-86 C compiler
	dw	crc
	db	0c1h,'crc',0
	dw	0,0

	end
;=========================================================================

/*
    CRCC -- C subroutine to calcute CRC-16 of string of byte using
    byte-wise method described in June 1983 IEEE Micro.  Uses crctab
    created by program CRCT.C  I suggest reading the article if you
    really want to know how it works.

    Programmer: Bryan Bingham	9 Nov 1983

    Input: a null terminated string
    Output: The unsigned CRC value 
*/

#include "crctab.h"		/* created by CRCT, a table of 256 ints */

unsigned int crcc(line)
char *line ;
{
    unsigned int	
	crc ,			/* result stored here */
	x ;			/* index to table crctab */

    char
	*p ;			/* into line */


    crc = 0 ;
    while (*p = *line++) {
	x = *p ^ (crc & 0xff) ;		/* make x from byte and low 8 crc */
	crc >>= 8 ;			/* shift crc 8 to right */
	crc ^= crctab[x] ;		/* x guaranteed 0 <= x <= 255 */
    }	
    return (crc) ;
} 

/*
    CRCT -- program to tabulate values necessary for CRC-16 byte-wise
    calculations.

    Programmer: Bryan Bingham	9 Nov 1983

    Will output a table, suitable for editing, of 256 hex values to
    use with table driven CRC algorithm -- see crc.c and Jun 1983
    IEEE Micro magazine for how table is used.

    Editing required includes filling in the spaces between the 0x
    and the hex numbers generated.  Also make the whole thing a
    declaration for an integer array crctab[256].  
*/

#include <stdio.h>

main()
{
    int 
    	x, x1, x2, x3, x4, x5, x6, x7, x8, v, i 
	;

    v = i = 0 ;
    printf("\n\t") ;
    for (x8 = 0 ; x8 < 2 ; x8++)
	for (x7 = 0 ; x7 < 2 ; x7++)
	    for(x6 = 0 ; x6 < 2 ; x6++) 
		for (x5 = 0 ; x5 < 2 ; x5++)
		    for (x4 = 0 ; x4 < 2 ; x4++)
			for (x3 = 0 ; x3 < 2 ; x3++) 
			    for(x2 = 0 ; x2 < 2 ; x2++)
				for (x1 = 0 ; x1 < 2 ; x1++) {
				    x = x8^x7^x6^x5^x4^x3^x2^x1 ;
                                    v = x << 15 ;
	/* vertical bar not : */    v |= (x7^x6^x5^x4^x3^x2^x1) << 14 ;
				    v |= (x8^x7) << 13 ;
				    v |= (x7^x6) << 12 ;
				    v |= (x6^x5) << 11 ;
				    v |= (x5^x4) << 10 ;
				    v |= (x4^x3) << 09 ;
				    v |= (x3^x2) << 08 ;
			    	    v |= (x2^x1) << 07 ;
				    v |= x1 << 6 ;
				    v |= x ;
				    if ( !(i++%8) ) {
					printf("\n\t") ;
					i = 1 ;
				    }
				    printf("0x%4x, ", v) ;
				    v = 0 ;
				}

}	/* end of program! */

/*  CRC-16 values for CRC-16 table driven byte-wise algorithm. See CRCC.C */
/*  Created with crct.c and then  hand edited to make legal C code. */

/*  Programmer: Bryan Bingham  8 Nov 1983  LANL */
	 

unsigned int crctab[256] = {
	
	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 
	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 
	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 
	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 
	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 
	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 
	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 
	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 
	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 
	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 
	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 
	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 
	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 
	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 
	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 
	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 
	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 
	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 
	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 
	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 
	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 
	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 
	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 
	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 
	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 
	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 
	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 
	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 
	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 
	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 
	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
        0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
	} ;


	Bryan Bingham  {ucbvax!lbl-csam,purdue,cmcl2}!lanl-a!bb @ LANL