/****************************************************************************/
/*							   Start of crcmodel.c							*/
/****************************************************************************/
/*																			*/
/* Author : Ross Williams (ross@guest.adelaide.edu.au.).					*/
/* Date   : 3 June 1993.													*/
/* Status : Public domain.													*/
/*																			*/
/* Description : This is the implementation (.c) file for the reference 	*/
/* implementation of the Rocksoft^tm Model CRC Algorithm. For more			*/
/* information on the Rocksoft^tm Model CRC Algorithm, see the document 	*/
/* titled "A Painless Guide to CRC Error Detection Algorithms" by Ross      */
/* Williams (ross@guest.adelaide.edu.au.). This document is likely to be in */
/* "ftp.adelaide.edu.au/pub/rocksoft".                                      */
/*																			*/
/* Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia.	*/
/*																			*/
/****************************************************************************/
/*																			*/
/* Implementation Notes 													*/
/* -------------------- 													*/
/* To avoid inconsistencies, the specification of each function is not		*/
/* echoed here. See the header file for a description of these functions.	*/
/* This package is light on checking because I want to keep it short and	*/
/* simple and portable (i.e. it would be too messy to distribute my entire	*/
/* C culture (e.g. assertions package) with this package.					*/
/*																			*/
/****************************************************************************/

#include "crcmodel.h"

/****************************************************************************/
/* The following definitions make the code more readable.					*/

#define BITMASK(X) (1L << (X))
#define MASK32 0xFFFFFFFFL
#define LOCAL static

/****************************************************************************/

/* Returns the value v with the bottom b [0,32] bits reflected. */
/* Example: reflect(0x3e23L,3) == 0x3e26						*/

LOCAL ulong reflect(
    ulong v,
    int   b)
{
 int   i;
 ulong t = v;
 for (i=0; i<b; i++)
   {
	if (t & 1L)
	   v|=	BITMASK((b-1)-i);
	else
	   v&= ~BITMASK((b-1)-i);

	t>>=1;

   }
 return v;
}

/****************************************************************************/

/* Returns a longword whose value is (2^p_cm->cm_width)-1.	   */
/* The trick is to do this portably (e.g. without doing <<32). */

LOCAL ulong widmask(p_cm_t p_cm)
{
 return (((1L<<(p_cm->cm_width-1))-1L)<<1)|1L;
}

/****************************************************************************/

void cm_ini (p_cm_t p_cm)
{
 p_cm->cm_reg = p_cm->cm_init;
}

/****************************************************************************/

void cm_nxt(p_cm_t p_cm, int ch)
{
 int   i;
 ulong uch	= (ulong) ch;
 ulong topbit = BITMASK(p_cm->cm_width-1);

 if (p_cm->cm_refin) uch = reflect(uch,8);
 p_cm->cm_reg ^= (uch << (p_cm->cm_width-8));
 for (i=0; i<8; i++)
   {
	if (p_cm->cm_reg & topbit)
	   p_cm->cm_reg = (p_cm->cm_reg << 1) ^ p_cm->cm_poly;
	else
	   p_cm->cm_reg <<= 1;
	p_cm->cm_reg &= widmask(p_cm);
   }
}

/****************************************************************************/

void cm_blk(
p_cm_t	 p_cm,
p_ubyte_ blk_adr,
ulong	 blk_len)
{
 while (blk_len--) cm_nxt(p_cm,*blk_adr++);
}

/****************************************************************************/

ulong cm_crc(p_cm_t p_cm)
{
 if (p_cm->cm_refot)
	return p_cm->cm_xorot ^ reflect(p_cm->cm_reg,p_cm->cm_width);
 else
	return p_cm->cm_xorot ^ p_cm->cm_reg;
}

/****************************************************************************/

ulong cm_tab(p_cm_t p_cm, int index)
{
 int   i;
 ulong r;
 ulong topbit = BITMASK(p_cm->cm_width-1);
 ulong inbyte = (ulong) index;

 if (p_cm->cm_refin) inbyte = reflect(inbyte,8);
 r = inbyte << (p_cm->cm_width-8);
 for (i=0; i<8; i++)
	if (r & topbit)
	   r = (r << 1) ^ p_cm->cm_poly;
	else
	   r<<=1;
 if (p_cm->cm_refin) r = reflect(r,p_cm->cm_width);
 return r & widmask(p_cm);
}

/****************************************************************************/
/*							   End of crcmodel.c							*/
/****************************************************************************/

