home *** CD-ROM | disk | FTP | other *** search
- Program CRC;
-
- { CRC generation program, version 7b (optimized + timing + documentation)
-
-
- This set of implementations was written by David Dantowitz, and
- has been placed in the public domain, to be used at the user's
- discretion.
-
- This program demonstrates various ways by which Cyclic
- Redundancy Checks (CRC) may be computed and their relative speeds.
-
- Please note the cautionary notice involving the routine SET_TIMER.
- This routine should be used only by users who understand its
- consequences and who wish to experiment with interrupt and timer
- routines. The routine has been written for use on an IBM PC or
- compatible.
-
- The variable TIME is the location of the low 16 bits of the TIMER
- location incremented by DOS 2.0 with each clock tick. It is defined
- in the source code for the IBM PC ROM BIOS. This should work with
- most compatibles as well as later versions of the operating system.
-
-
- Here are some sample results. These were obtained using TURBO 3.0
- under DOS 2.0 on a SEEQUA Chameleon. (Your mileage may vary.)
- (Note that the CRC is printed to assure that all implementations
- are working properly.)
-
-
- D a t a S t r e a m L e n g t h
-
- 512 1024 2048 4096 32767
-
- No table 0.33 0.65 1.31 2.62 20.93 CRC = -31717
- Nybble table 0.10 0.18 0.38 0.76 6.03 CRC = -31717
- Two Nybble tables 0.10 0.18 0.36 0.74 5.88 CRC = -31717
- Byte table 0.08 0.16 0.32 0.64 5.12 CRC = -31717
- Nybble string 0.03 0.05 0.09 0.18 1.50 CRC = -31717
- Byte string 0.01 0.03 0.05 0.09 0.73 CRC = -31717
-
- }
-
- Const
- max = 32767;
-
- Type
- Bytes = Array [1..max] of Byte;
-
- Var
- time : Integer Absolute $0040:$006c; { TIMER_LOW
- IBM PC ROM BIOS location }
-
- initial_clock, stop, j, i : Integer;
-
- length : Array [1..5] of Integer;
-
- table_16 : Array [0..15] of Integer;
- table_32a : Array [0..16] of Integer;
- table_32b : Array [0..16] of Integer;
- table_256 : Array [0 .. 255] of Integer;
-
- CRC_value : Integer;
-
- byte_string : Bytes;
-
- POLY : Integer;
-
- {
- CRC polynomials in this program are represented by replacing
- each term that is non-zero with a 1 and each zero term with a 0.
- Note that the highest order bits represent the low order terms
- of the polynomial.
-
- Thus X^3+X^1+1 becomes 1101 and X^4+X^1+1 becomes 11001.
-
- Since all polynomials have a highest term (X^a) we drop the
- highest term during computation (shift right one bit).
-
-
- Here are some examples :
-
-
- Polynomial Representation Hex
-
- X^5 + X^2 + 1 10100 $14
-
- X^7 + 1 1000000 $40
-
- X^3+X^2+X^1+1 111 $7
-
- X^6+X^5+X^3+1 100101 $25
-
-
- For a good discussion of polynomial selection see "Cyclic
- Codes for Error Detection", by W. W. Peterson and
- D. T. Brown, Proceedings of the IEEE, volume 49, pp 228-235,
- January 1961.
-
- A reference on table driven CRC computation is "A Cyclic
- Redundancy Checking (CRC) Algorithm" by A. B. Marton and
- T. K. Frambs, The Honeywell Computer Journal, volume 5,
- number 3, 1971.
-
- Also used to prepare these examples was "Computer Networks",
- by Andrew S. Tanenbaum, Prentice Hall, Inc. Englewood Cliffs,
- New Jersey, 1981.
-
- The following three polynomials are international standards:
-
-
- CRC-12 = X^12 + X^11 + X^3 + X^2 + X^1 + 1
- CRC-16 = X^16 + X^15 + X^2 + 1
- CRC-CCITT = X^16 + X^12 + X^5 + 1
-
- In Binary and hexadecimal :
-
- Binary Hex
-
- CRC-12 = 1111 0000 0001 $0F01
- CRC-16 = 1010 0000 0000 0001 $A001
- CRC-CCITT = 1000 0100 0000 1000 $8404 (Used below)
-
- The first is used with 6-bit characters and the second two
- with 8-bit characters. All of the above will detect any
- odd number of errors. The second two will catch all 16-bit
- bursts, a high percentage of 17-bit bursts (~99.997%) and
- also a large percentage of 18-bit or larger bursts (~99.998%).
- The paper mentioned above (Peterson and Brown) discusses how
- to compute the statistics presented which have been quoted
- from Tanenbaum.
-
- (A burst of length N is defined a sequence of N bits, where
- the first and last bits are incorrect and the bits in the
- middle are any possible combination of correct and incorrect.
- See the paper by Peterson and Brown for more information)
-
-
- Note that when using a polynomial of degree N, the CRC is the
- first N bits of the value returned by the routines below.
- (e.g. with CRC-12, the CRC is bits 0 to 11 of the CRC value,
- with the other two mentioned above, the CRC is all 16 bits.)
-
-
- Here is a quick idea of what is being calculated ...
-
- The CRC is the residual from division of the data stream by
- the CRC polynomial. The data stream is also thought of as a
- polynomial, with the highest order term being the lowest bit
- of the first byte of the data stream and the lowest order term
- of the polynomial being the high bit of the last byte of data.
- The actual division is performed on the data stream polynomial
- multiplied by X^y where y is the degree of the CRC polynomial.
-
-
- CRC use ...
-
- The CRC is then appended to the end of the data stream. When
- the receiver gets the data stream, the CRC is again computed
- and matched against the received CRC, if the two do not match
- then an error has most likely occurred.
-
-
-
-
-
- }
-
-
- {
-
- This work was prompted by a submission by David Kirschbaum,
- who unknowingly submitted a program that contained an error.
- I have not determined if what it computed has any reliable
- error-detecting capabilities, only that it was an attempt to
- compute a CRC, that really did not work. The original code
- is correctly used in the program KERMIT (Columbia University)
- to compute the CRC-CCITT polynomial CRC.
-
-
- My address is
-
- David Dantowitz
- Digital Equipment Corporation
- Dantowitz%eagle1.dec@decwrl
-
-
- The views and ideas expressed here are my own and do not necessarily
- reflect those of the Digital Equipment Corporation.
-
-
- David Kirschbaum
- Toad Hall
- ABN.ISCAMS@USC-ISID.ARPA
- }
-
- Procedure set_timer(count : Integer);
-
- {
- This routine sets the clock (timer) count-down value to
- count. The DOS value is 0 (this is the maximum value ...
- it really means 65536). This routine is used to obtain
- better resolution in timing.
-
- WARNING : The setting of count to too small a value will
- HANG your system. Please study interrupts in
- real time systems before using this routine.
-
- WARNING : This routine was written to run on an IBM PC or
- compatible. Disable this routine when this
- program is run on other machines.
- }
-
- Begin
-
- inline($b0/$36/ { mov al,36 }
- $e6/$43/ { out 43,al }
- $8b/$86/count/ { mov ax,bp[count] }
- $e6/$40/ { out 40,al }
- $88/$e0/ { mov al,ah }
- $e6/$40); { out 40,al }
-
- End;
-
- Procedure simple_crc(b:byte);
-
- {
- This routine computes the CRC value bit by bit. The initial value
- is assumed to be in a global variable CRC_value and the global variable
- POLY contains the representation of the polynomial be used. The routine
- is called for each byte. The result is placed in the global CRC_value.
- }
-
- Var
- i : Integer;
-
- Begin
- CRC_value := b xor CRC_value;
-
- For i := 1 to 8 Do
- Begin
- If (CRC_value and 1) = 1
- then CRC_value := (CRC_value shr 1) xor POLY
- else CRC_value := CRC_value shr 1;
- End;
-
- End;
-
- Procedure generate_table_16(POLY : Integer);
-
- {
- This routine computes the remainder values of 0 through 15 divided
- by the polynomial represented by POLY. These values are placed in a
- table and used to compute the CRC of a block of data efficiently.
-
-
- This implementation only permits polynomials up to degree 16.
- }
-
-
- Var
- val, i, result : Integer;
-
- Begin
- For val := 0 to 15 Do
- Begin
- result := val;
- For i := 1 to 4 Do
- Begin
- If (result and 1) = 1
- then result := (result shr 1) xor POLY
- else result := result shr 1;
- End;
-
- table_16[val] := result;
- End
- End;
-
-
- Procedure generate_table_32(POLY : Integer);
-
- {
- This routine computes the remainder values of 0 through 15 divided
- by the polynomial represented by POLY. These values are placed in two
- tables and used to compute the CRC of a block of data efficiently.
-
-
- This implementation only permits polynomials up to degree 16.
- }
-
-
- Var
- val, i, result, divide : Integer;
-
- Begin
- {
- Table_32a divides the number for eight bits (not four).
- Note that Table_32b is identical to Table_16.
- }
-
- For val := 0 to 15 Do
- Begin
- result := val;
- For i := 1 to 4 Do
- Begin
- If (result and 1) = 1
- then result := (result shr 1) xor POLY
- else result := result shr 1;
- End;
-
- table_32b[val] := result;
- End;
-
- For val := 0 to 15 Do
- Begin
- result := table_32b[val];
- For i := 1 to 4 Do
- Begin
- If (result and 1) = 1
- then result := (result shr 1) xor POLY
- else result := result shr 1;
- End;
-
- table_32a[val] := result;
- End;
-
- End;
-
- Procedure generate_table_256(POLY : Integer);
-
- {
- This routine computes the remainder values of 0 through 255 divided
- by the polynomial represented by POLY. These values are placed in a
- table and used to compute the CRC of a block of data efficiently.
- More space is used, but the CRC computation will be faster.
-
-
-
- This implementation only permits polynomials up to degree 16.
- }
-
-
- Var
- val, i, result, divide : Integer;
-
- Begin
- For val := 0 to 255 Do
- Begin
- result := val;
- For i := 1 to 8 Do
- Begin
- If (result and 1) = 1
- then result := (result shr 1) xor POLY
- else result := result shr 1;
- End;
-
- table_256[val] := result;
- End
- End;
-
-
- Procedure Compute_crc_16(next_byte : byte);
-
- {
- This routine calculates the CRC and stores the result in a global
- variable CRC_value. You must first initialize CRC_value to 0 or the
- proper initial value for the CRC and then call this routine with
- each byte.
-
- This routine uses table_16.
-
- }
-
- Begin
-
- inline(
- $8b/$16/CRC_value/ {mov dx,CRC_value }
- $32/$56/<next_byte/ {xor dl,next_byte[bp] CRC = CRC XOR Next_byte }
- $be/table_16/ {mov si,offset table_16 (table address) }
- $30/$ff/ {xor bh,bh (bh <- 0) }
-
- $88/$d3/ {mov bl,dl }
- $80/$e3/$0f/ {and bl,0f }
- $d0/$e3/ {shl bl,1 }
- $b1/$04/ {mov cl,4 }
- $d3/$ea/ {shr dx,cl }
- $33/$10/ {xor dx,[bx+si] CRC = (CRC shr 4) XOR
- table[CRC and 0F] }
-
- $88/$d3/ {mov bl,dl }
- $80/$e3/$0f/ {and bl,0f }
- $d0/$e3/ {shl bl,1 }
- $b1/$04/ {mov cl,4 }
- $d3/$ea/ {shr dx,cl }
- $33/$10/ {xor dx,[bx+si] CRC = (CRC shr 4) XOR
- table[CRC and 0F] }
-
-
- $89/$16/CRC_value); {mov CRC_value,dx Update CRC in memory }
-
- { basic algorithm expressed above
-
- temp := crc XOR next_byte;
-
- For i := 1 to 2 Do
- temp := (temp shr 4) XOR table [temp and $0F];
-
- CRC_value := temp;
- }
- End;
-
- Procedure Compute_crc_32(next_byte : byte);
- {
- This is the algorithm used in KERMIT and attempted by the routine
- DoCRC from Toad Hall.
-
- The code here completely new. This routine uses table_32a and
- table_32b.
- }
-
- Begin
-
- inline(
- $8b/$16/CRC_value/ {mov dx,CRC_value }
-
- $32/$56/<next_byte/ {xor dl,next_byte[bp] CRC = CRC XOR Next_byte }
-
- { intermediate steps, see comments for overall effect }
-
- $31/$db/ {xor bx,bx (bx <- 0) }
- $86/$d3/ {xchg bl,dl (bx <- dx and 0FF) }
- $86/$f2/ {xchg dl,dh (dx <- dx shr 8) }
-
- $88/$d8/ {mov al,bl }
- $80/$e3/$0f/ {and bl,0fh }
- $d0/$e3/ {shl bl,1 (bx <- bx+bx) }
- $be/table_32a/ {mov si,offset table_32a (table address) }
- $33/$10/ {xor dx,[bx+si] }
-
- $88/$c3/ {mov bl,al }
- $80/$e3/$f0/ {and bl,0f0h }
- $b1/$03/ {mov cl,3 }
- $d2/$eb/ {shr bl,cl }
- $be/table_32b/ {mov si,offset table_32b (table address) }
- $33/$10/ {xor dx,[bx+si] }
-
- $89/$16/CRC_value); {mov CRC_value,dx Update CRC in memory }
- End;
-
-
-
- Procedure Compute_crc_256(next_byte : byte);
-
- {
- This routine calculates the CRC and stores the result in a global
- variable CRC_value. You must first initialize CRC_value to 0 or the
- proper initial value for the CRC and then call this routine with
- each byte.
-
- This routine uses table_256.
- }
-
- Begin
-
- inline(
- $8b/$16/CRC_value/ {mov dx,CRC_value }
- $be/table_256/ {mov si,offset table_256 (table address) }
-
-
- $32/$56/<next_byte/ {xor dl,next_byte[bp] CRC = CRC XOR Next_byte }
-
- { intermediate steps, see comments for overall effect }
-
- $31/$db/ {xor bx,bx (bx <- 0) }
- $86/$d3/ {xchg bl,dl (bx <- dx and 0FF) }
- $86/$f2/ {xchg dl,dh (dx <- dx shr 8) }
- $d1/$e3/ {shl bx,1 (bx <- bx+bx) }
- $33/$10/ {xor dx,[bx+si] CRC = (CRC shr 8) XOR
- table[CRC and 0FF] }
-
- $89/$16/CRC_value); {mov CRC_value,dx Update CRC in memory }
-
- { basic algorithm expressed above
-
- temp := crc XOR next_byte;
-
- temp := (temp shr 8) XOR table_256 [temp and $FF];
-
- CRC_value := temp;
- }
- End;
-
- Function crc_string_16(Var s : Bytes; length, initial_crc : Integer) : Integer;
-
- {
- This routine computes the CRC value and returns it as the function
- value. The routine takes an array of Bytes, a length and an initial
- value for the CRC. The routine requires that a table of 16 values
- be set up by a previous call to Generate_table_16.
-
- This routine uses table_16.
- }
-
- Begin
-
- inline(
-
- $c4/$7e/<s/ {les di,s[bp] (es:di points to array) }
- $8b/$46/<initial_crc/ {mov ax,initial_crc[bp] (initial CRC value) }
- $8b/$56/<length/ {mov dx,length[bp] (count) }
- $be/table_16/ {mov si,offset table_16 (table address) }
- $30/$ff/ {xor bh,bh (bh <- 0) }
-
-
- { next: }
-
- $26/$32/$05/ {xor al,es:[di] CRC = CRC XOR next byte }
- $47/ {inc di (point to next byte) }
-
-
- $88/$c3/ {mov bl,al }
- $80/$e3/$0f/ {and bl,0f }
- $d0/$e3/ {shl bl,1 }
- $b1/$04/ {mov cl,4 }
- $d3/$e8/ {shr ax,cl }
- $33/$00/ {xor ax,[bx+si] CRC = (CRC shr 4) XOR
- table[CRC and 0F] }
-
-
- $88/$c3/ {mov bl,al }
- $80/$e3/$0f/ {and bl,0f }
- $d0/$e3/ {shl bl,1 }
- $b1/$04/ {mov cl,4 }
- $d3/$e8/ {shr ax,cl }
- $33/$00/ {xor ax,[bx+si] CRC = (CRC shr 4) XOR
- table[CRC and 0F] }
-
- $4a/ {dec dx (count <- count -1) }
- $75/$df/ {jnz next }
-
- $89/$46/<s+4); {mov s+4[bp],ax (crc_string_16 := CRC) }
-
- { basic algorithm expressed above
-
-
- temp := initial_crc;
-
- For each byte Do
-
- Begin
- temp := temp XOR next_byte;
-
- For i := 1 to 2 Do
- temp := (temp shr 4) XOR table [temp and $0F];
- End;
-
- Crc_string_16 := temp;
- }
-
- End;
-
-
- Function crc_string_256(Var s : Bytes; length, initial_crc : Integer) : Integer;
-
- {
- This routine computes the CRC value and returns it as the function
- value. The routine takes an array of Bytes, a length and an initial
- value for the CRC. The routine requires that a table of 256 values
- be set up by a previous call to Generate_table_256.
-
- This routine uses table_256.
- }
-
- Begin
-
- inline(
-
- $c4/$7e/<s/ {les di,s[bp] (es:di points to array) }
- $8b/$46/<initial_crc/ {mov ax,initial_crc[bp] (initial CRC value) }
- $8b/$4e/<length/ {mov cx,length[bp] (count) }
- $be/table_256/ {mov si,offset table_256 (table address) }
-
-
- { next: }
-
- $26/$32/$05/ {xor al,es:[di] CRC = CRC XOR next byte }
- $47/ {inc di (point to next byte) }
-
- { intermediate steps, see comments for overall effect }
-
- $31/$db/ {xor bx,bx (bx <- 0) }
- $86/$d8/ {xchg al,bl (bx <- ax and 0FF) }
- $86/$e0/ {xchg al,ah (ax <- ax shr 8) }
- $d1/$e3/ {shl bx,1 (bx <- bx+bx) }
-
- $33/$00/ {xor ax,[bx+si] CRC = (CRC shr 8) XOR
- table[CRC and 0FF] }
-
- $e2/$f0/ {loop next (count <- count -1) }
-
- $89/$46/<s+4); {mov s+4[bp],ax (crc_string_256 := CRC) }
-
-
- { basic algorithm expressed above
-
- crc := initial_crc
-
- For each byte Do
- Begin
- crc := crc XOR next_byte;
-
- crc := (crc shr 8) XOR table_256 [crc and $FF];
- End;
-
- crc_string_256 := crc;
- }
- End;
-
-
-
- Begin
-
- Writeln('Generating the data string, please wait ...');
- Writeln;
- Writeln;
-
- Generate_table_16($8404);
- Generate_table_32($8404);
- Generate_table_256($8404);
-
- For j := 1 to max Do
- byte_string[j] := trunc(random*256); { Create a data string }
-
- length[1] := 512;
- length[2] := 1024;
- length[3] := 2048;
- length[4] := 4096;
- length[5] := 32767;
-
- Writeln;
- Writeln(' D a t a S t r e a m L e n g t h');
- Writeln;
- Write(' ');
-
- For j := 1 to 5 Do
- Write(' ', length[j]:8);
-
- Writeln;
- Writeln;
-
- Initial_clock := time;
-
- Set_timer(5964); { each tick = ~0.005 seconds }
-
- {-----------------------------------------------------------------------------}
-
- CRC_value := 0;
- POLY := $8404;
-
- Write('No table ');
-
- For j := 1 to 5 Do
- Begin
- time := 0;
- For i := 1 to length[j] Do
- simple_crc(byte_string[i]);
- stop := time;
- Write(stop/200:5:2, ' ');
- End;
-
- Writeln('CRC = ', CRC_value);
-
- {-----------------------------------------------------------------------------}
-
- CRC_value := 0;
-
- Write('Nybble table ');
-
- For j := 1 to 5 Do
- Begin
- time := 0;
- For i := 1 to length[j] Do
- compute_crc_16(byte_string[i]);
- stop := time;
- Write(stop/200:5:2, ' ');
- End;
-
- Writeln('CRC = ', CRC_value);
-
- {-----------------------------------------------------------------------------}
-
- CRC_value := 0;
-
- Write('Two Nybble tables ');
-
- For j := 1 to 5 Do
- Begin
- time := 0;
- For i := 1 to length[j] Do
- compute_crc_32(byte_string[i]);
- stop := time;
- Write(stop/200:5:2, ' ');
- End;
-
- Writeln('CRC = ', CRC_value);
-
- {-----------------------------------------------------------------------------}
-
- CRC_value := 0;
-
- Write('Byte table ');
-
- For j := 1 to 5 Do
- Begin
- time := 0;
- For i := 1 to length[j] Do
- compute_crc_256(byte_string[i]);
- stop := time;
- Write(stop/200:5:2, ' ');
- End;
-
- Writeln('CRC = ', CRC_value);
-
- {-----------------------------------------------------------------------------}
-
- CRC_value := 0;
-
- Write('Nybble string ');
-
- For j := 1 to 5 Do
- Begin
- time := 0;
- CRC_value := crc_string_16(byte_string, length[j], CRC_value);
- stop := time;
- Write(stop/200:5:2, ' ');
- End;
-
- Writeln('CRC = ', CRC_value);
-
- {-----------------------------------------------------------------------------}
-
- CRC_value := 0;
-
- Write('Byte string ');
-
- For j := 1 to 5 Do
- Begin
- time := 0;
- CRC_value := crc_string_256(byte_string, length[j], CRC_value);
- stop := time;
- Write(stop/200:5:2, ' ');
- End;
-
- Writeln('CRC = ', CRC_value);
-
- {-----------------------------------------------------------------------------}
-
- set_timer(0); { restore the clock to the normal DOS value }
-
- time := initial_clock; { we may have lost a few minutes ... }
-
- End.
-