\ Forth Scientific Library Algorithm #44
\ (c) Copyright 1994 Gordon R Charlton. Permission is granted by
\ the author to use this software for any application provided this
\ copyright notice is preserved.
\ 4tH version Copyright 1997,2005 HanSoft & Partners
\ ANS Forth Program
\ Requiring ?DO
\ from the Core Extensions word set.
\ This is a collection of words to create 16 bit cyclic redundancy checksums
\ (crcs) from a stream of bytes. The code is adapted from "CRC Polynomials Made
\ Plain" by Wil Baden in the 1989 Forml Conference Proceedings, Pub. Forth
\ Interest Group 1990, pages 104-112. Modifications have been made to allow it
\ to run independantly of the cell width of the Forth system, and to include bit
\ order reversal of bytes and 16bit words, as required by some common protocols.
\ Descriptions of some common protocols may be found in Numerical Recipes in C,
\ The Art of Scientific Programming by Press, Vetterling, Teukolsky and
\ Flannery, 2nd Edition, Cambridge University Press 1992 20.3 Cyclic
\ Redundancy and Other Checksums pages 896-901.
[UNDEFINED] crc [IF]
\ CRCs are an exercise in bit-banging, so HEX is appropriate.
[HEX] HEX
100 STRING revtable
\ A lookup table for bit-reversed bytes.
: calc-rev8 ( ch--ch) 0 SWAP
8 0 DO DUP 1 AND
ROT 2* OR
SWAP 2/
LOOP
DROP ;
\ Brute force bit reversal of a byte.
: fillrev8table ( --) 100 0 DO I calc-rev8
I CHARS revtable + C!
LOOP ;
fillrev8table
\ Initialise the look-up table and clear out the code required to do so.
: rev8 ( ch--ch) CHARS revtable + C@ ;
\ Reverse the order bits in a byte by table-lookup for speed.
: >< ( n--n) DUP FF AND 8 LSHIFT
SWAP FF00 AND 8 RSHIFT OR ;
\ Swap the least significant 8 bits of a stack element with the next least
\ significant 8 bits. More significant bits are set to zero.
\ >< is a traditional name for this function, which is present as a primitive
\ on many 16 bit systems.
: rev16 ( n--n) DUP FF AND rev8 8 LSHIFT
SWAP FF00 AND 8 RSHIFT rev8 OR ;
\ Reverse the order of bits of the 16 least significant bits of a stack element
\ More significant bits are set to zero.
100 ARRAY crctable
\ A lookup table for crc values for various byte length bit patterns.
1021 CONSTANT crc-polynomial ( CCITT or: 8005 for CRC-16)
\ The CCITT standard crc-polynomial is presumed. Others, such as CRC-16, which
\ is used in IBMs BISYNCH, may be editted in here)
: calc-crc ( n ch--n) >< XOR
8 0 DO DUP 8000 AND
IF 2* FFFF AND crc-polynomial XOR
ELSE 2*
THEN
LOOP ;
\ n is a CRC. crc computes a new value, to include the byte ch one bit at a
\ time. This is a slow method, used only to initialise the lookup table.
\ fairly slow method, used to set up the lookup table.
\ FFFF AND is, of course, redundant on a 16 bit system, but as this word is
\ only used during compilation there is no benefit to be gained from removing
\ it from the source.
: fillcrctable ( --) 100 0 DO 0 I calc-crc I XOR
I CELLS crctable + !
LOOP ;
fillcrctable
\ Initialise the look-up table and clear out the code required to do so.
: crc ( n ch--n) >< XOR ><
DUP FF AND CELLS crctable + @
XOR ;
\ n is a CRC. crc computes a new value, to include the byte ch.
\ This is the basic accumulate crc function. The words that follow illustrate
\ its application, by generating crcs for strings of characters according to
\ various conventions.
: >xmodem ( addr n--n) 0 -ROT
OVER + SWAP
?DO
I C@ crc
1 CHARS +LOOP
;
\ The XMODEM convention uses a starting value of zero (all bits low).
: >x.25 ( addr n--n) FFFF -ROT
OVER + SWAP
?DO
I C@ rev8 crc
1 CHARS +LOOP
rev16 ;
\ X.25 uses a starting value of all bits high, and expects bytes in bit
\ reversed order (ie raw from a serial data port.) The computed checksum is
\ likewise bit reversed.
: >crc-ccitt ( addr n--n) 0 -ROT
OVER + SWAP
?DO
I C@ rev8 crc
1 CHARS +LOOP
rev16 ;
\ CRC-CCITT has a starting value of all bits low, and is bit reversed.
\ end of Cyclic Redundancy Checksums
[DEFINED] 4TH# [IF]
hide revtable
hide calc-rev8
hide fillrev8table
hide ><
hide crctable
hide crc-polynomial
hide calc-crc
hide fillcrctable
[THEN]
[THEN]
|