ELECTRONIC DESIGN: May 21, 2001, Ideas For Design, page 91 "PLD Code Implements Arbitrary CRC Functions" by Clive Bolton and Ken Sinclair, Bolton Engineering Inc., 72 Stone Pl., Melrose, MA 02176 e-mail: cbolton@world.std.com %———————————————————————————————————- % % PLD Code Implements Arbitrary CRC Functions % % Author: Clive Bolton and Ken Sinclair % % Bolton Engineering, Inc., % % 72 Stone Place, Melrose, MA 02176 % % E-mail: cbolton@world.std.com % % Filename: crc.tdf % %———————————————————————————————————- % % Implements a general-purpose serial-input CRC generator/checker. % % By setting several parameters, the design can implement a % % variety of CRC polynomials. % %———————————————————————————————————- % % Please note that the only CRC implementation we have actually % % used is the CRC-CCITT implementation; we believe the others are % % correct, but we have not had a chance to verify them. % % % % Check out this url for a good tutorial on how CRCs work: % % http://bbs-koi.uniinc.msk.ru/tech1/1994/er_cont/crc_how.htm % %———————————————————————————————————- % % Update: by Ken Sinclair % % Added SEED and INVERT parameters needed for correct % % implementation of the CRC-CCITT specification. Also changed % % the implementation to the simpler current-remainder bit-serial % % one recommended in the following reference, excerpted below: % % % % Ritter, T. 1986. The Great CRC Mystery. Dr. Dobb’s Journal % % of Software Tools. February. 11(2): 26-34, 76-83. % % % % “The CRC result can be obtained without shifting in the two zero % % bytes by rearranging the CRC register and feeding the data in at % % the top end of the system (see Figure 2, below). By shifting the % % CRC register we can shift zeros in from the right. The data bit % % will be compared to the MSB in the CRC register, and only if they % % differ will the polynomial be subtracted. As before, this acts % % to keep the full remainder in the register; however, the % % remainder is now correct after each bit, and requires no trailing % % zeros. % % % % Example Poly = x^5 + x^4 + x^2 + 1 = 110101 % % INPUT % % | x^4 x^3 x^2 x^1 x^0 % % V +—--+ +—--+ +—--+ +—--+ +—--+ % % +<-XOR<-|Q D|<-XOR<-|Q D|<——|Q D|<-XOR<-||Q D|<——|Q D|<-+ % % | | | ^ | | | | ^ || | | | | % % | +—--+ | +—--+ +—--+ | +—--+ +—--+ | % % | | | | % % +———————-———————+——-————————————————+——————————————————+ % % (endquote) % % % % ———— Defines for CRC-16 polynomial X^16+X^15+X^2+1 ————— % % With MATCH_PIPELINE == 1, CRC-16 runs at 125 MHz in 10K10-3 % % and takes 21 LCs % % WIDTH = 16; % % POLYNOMIAL = B”1000000000000101”; % % SEED = H”FFFF”; % % INVERT = “YES”; % % RESIDUE = “800D”; % % % % ————————- Defines for CRC-32 polynomial ————————- % % X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X+1 % % With MATCH_PIPELINE == 2, CRC-32 runs at 125 MHz in 10K10-3 % % With MATCH_PIPELINE == 1, CRC-32 runs at 99 MHz in 10K10-3 % % and takes 45 LCs % % WIDTH = 32; % % POLYNOMIAL = B”00000100110000010001110110110111”; % % SEED = H”FFFFFFFF”; % % RESIDUE = H”DEBB20E3”; % % INVERT = “YES”; % % % % ——— Defines for CRC-CCITT polynomial X^16+X^12+X^5+1 ————- % % This is the only polynomial actually tested in hardware % % WIDTH = 16; % % POLYNOMIAL = B”0001000000100001”; % % SEED = H”FFFF”; % % INVERT = “YES”; % % RESIDUE = H”1D0F”; % %———————————————————————————————————- % PARAMETERS ( WIDTH = 16, — Defaults to CRC-CCITT POLYNOMIAL = B”0001000000100001”, — Polynomial, MSB left out MATCH_PIPELINE = 1, — # clks after which out=active SEED = H”FFFF”, — Initial value (for sinit) INVERT = “YES”, — 1’s complement result RESIDUE = H”1D0F” — Constant remainder ); SUBDESIGN CRC ( —————————————- INPUT PINS —————————— clock : INPUT; enable : INPUT = VCC; — Shift enable shiftin : INPUT; — Input data aclr : INPUT = GND; — Async Clear sinit : INPUT = GND; — Loads SEED at start of xfer calculate : INPUT = VCC; — 1 to calc, 0 to shift —————————————- OUTPUT PINS —————————- q[WIDTH-1..0] : OUTPUT; — CRC result match : OUTPUT; — CRC == RESIDUE — (not gated by enable) shiftout : OUTPUT; ) VARIABLE ——————————————— NODES ——————————— s[WIDTH-1..0] : NODE; poly[WIDTH-1..0] : NODE; feedback : NODE; BEGIN poly[] = POLYNOMIAL; FOR i IN 0 to (WIDTH-1) GENERATE q[i] = DFFE(s[i], clock, !aclr, VCC, enable); END GENERATE; — Pipeline this value on system clock just to relax timing requirements feedback = DFF((shiftin XOR q[WIDTH-1]) AND calculate, clock, !aclr, VCC); IF sinit THEN s[] = SEED; ELSE s[0] = feedback; FOR i IN 0 to (WIDTH-2) GENERATE s[i+1] = q[i] XOR (feedback AND poly[i+1]); END GENERATE; END IF; IF INVERT == “YES” GENERATE shiftout = NOT q[WIDTH-1]; ELSE GENERATE shiftout = q[WIDTH-1]; END GENERATE; IF USED(match) GENERATE match =LPM_COMPARE(.dataa[]=q[],.datab[]=RESIDUE,.clock=clock,.aclr=aclr) WITH (LPM_WIDTH=WIDTH,LPM_PIPELINE=MATCH_PIPELINE, ONE_INPUT_IS_CONSTANT=”YES”) returns (.aeb); END GENERATE; END; %——————————————————————————————————— %