home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / turbopas / crc2.pas < prev    next >
Pascal/Delphi Source File  |  1994-03-05  |  22KB  |  763 lines

  1. Program CRC;
  2.  
  3. { CRC generation program, version 7b (optimized + timing + documentation)
  4.  
  5.  
  6.    This set of implementations was written by David Dantowitz, and
  7.    has been placed in the public domain, to be used at the user's
  8.    discretion.
  9.  
  10.    This program demonstrates various ways by which Cyclic
  11.    Redundancy Checks (CRC) may be computed and their relative speeds.
  12.  
  13.    Please note the cautionary notice involving the routine SET_TIMER.  
  14.    This routine should be used only by users who understand its 
  15.    consequences and who wish to experiment with interrupt and timer 
  16.    routines.  The routine has been written for use on an IBM PC or 
  17.    compatible.   
  18.  
  19.    The variable TIME is the location of the low 16 bits of the TIMER
  20.    location incremented by DOS 2.0 with each clock tick.  It is defined 
  21.    in the source code for the IBM PC ROM BIOS.  This should work with 
  22.    most compatibles as well as later versions of the operating system.
  23.  
  24.  
  25.    Here are some sample results.  These were obtained using TURBO 3.0
  26.    under DOS 2.0 on a SEEQUA Chameleon.   (Your mileage may vary.)
  27.    (Note that the CRC is printed to assure that all implementations
  28.    are working properly.)
  29.  
  30.  
  31.                       D a t a   S t r e a m   L e n g t h
  32.  
  33.                     512      1024      2048      4096     32767
  34.  
  35. No table           0.33      0.65      1.31      2.62     20.93     CRC = -31717
  36. Nybble table       0.10      0.18      0.38      0.76      6.03     CRC = -31717
  37. Two Nybble tables  0.10      0.18      0.36      0.74      5.88     CRC = -31717
  38. Byte table         0.08      0.16      0.32      0.64      5.12     CRC = -31717
  39. Nybble string      0.03      0.05      0.09      0.18      1.50     CRC = -31717
  40. Byte string        0.01      0.03      0.05      0.09      0.73     CRC = -31717
  41.  
  42. }
  43.  
  44. Const
  45.       max = 32767;
  46.  
  47. Type
  48.       Bytes = Array [1..max] of Byte;
  49.  
  50. Var
  51.       time : Integer Absolute $0040:$006c;  { TIMER_LOW
  52.                                               IBM PC ROM BIOS location }
  53.  
  54.       initial_clock, stop, j, i : Integer;
  55.  
  56.       length : Array [1..5] of Integer;
  57.  
  58.       table_16 : Array [0..15] of Integer;
  59.       table_32a : Array [0..16] of Integer;
  60.       table_32b : Array [0..16] of Integer;
  61.       table_256 : Array [0 .. 255] of Integer;
  62.  
  63.       CRC_value : Integer;
  64.  
  65.       byte_string : Bytes;
  66.  
  67.       POLY : Integer;
  68.  
  69. {
  70.    CRC polynomials in this program are represented by replacing
  71.    each term that is non-zero with a 1 and each zero term with a 0.
  72.    Note that the highest order bits represent the low order terms 
  73.    of the polynomial.
  74.  
  75.    Thus X^3+X^1+1 becomes 1101 and X^4+X^1+1 becomes 11001.
  76.  
  77.    Since all polynomials have a highest term (X^a) we drop the
  78.    highest term during computation (shift right one bit).
  79.  
  80.  
  81.    Here are some examples :
  82.  
  83.  
  84.            Polynomial                Representation     Hex
  85.  
  86.           X^5 + X^2 + 1                  10100          $14
  87.  
  88.             X^7 + 1                     1000000         $40
  89.  
  90.           X^3+X^2+X^1+1                   111           $7
  91.  
  92.           X^6+X^5+X^3+1                 100101          $25
  93.  
  94.  
  95.    For a good discussion of polynomial selection see "Cyclic
  96.    Codes for Error Detection", by W. W. Peterson and
  97.    D. T. Brown, Proceedings of the IEEE, volume 49, pp 228-235,
  98.    January 1961.
  99.  
  100.    A reference on table driven CRC computation is "A Cyclic
  101.    Redundancy Checking (CRC) Algorithm" by A. B. Marton and
  102.    T. K. Frambs, The Honeywell Computer Journal, volume 5,
  103.    number 3, 1971.
  104.  
  105.    Also used to prepare these examples was "Computer Networks",
  106.    by Andrew S. Tanenbaum, Prentice Hall, Inc.  Englewood Cliffs,
  107.    New Jersey, 1981.
  108.  
  109.    The following three polynomials are international standards:
  110.  
  111.  
  112.         CRC-12 = X^12 + X^11 + X^3 + X^2 + X^1 + 1
  113.         CRC-16 = X^16 + X^15 + X^2 + 1
  114.         CRC-CCITT = X^16 + X^12 + X^5 + 1
  115.  
  116.    In Binary and hexadecimal :
  117.  
  118.                    Binary                     Hex
  119.  
  120.         CRC-12    = 1111 0000 0001           $0F01
  121.         CRC-16    = 1010 0000 0000 0001      $A001
  122.         CRC-CCITT = 1000 0100 0000 1000      $8404    (Used below)
  123.  
  124.    The first is used with 6-bit characters and the second two
  125.    with 8-bit characters.  All of the above will detect any
  126.    odd number of errors.  The second two will catch all 16-bit
  127.    bursts, a high percentage of 17-bit bursts (~99.997%) and
  128.    also a large percentage of 18-bit or larger bursts (~99.998%).
  129.    The paper mentioned above (Peterson and Brown) discusses how 
  130.    to compute the statistics presented which have been quoted 
  131.    from Tanenbaum.
  132.  
  133.    (A burst of length N is defined a sequence of N bits, where
  134.    the first and last bits are incorrect and the bits in the
  135.    middle are any possible combination of correct and incorrect.
  136.    See the paper by Peterson and Brown for more information)
  137.  
  138.  
  139.    Note that when using a polynomial of degree N, the CRC is the
  140.    first N bits of the value returned by the routines below.
  141.    (e.g. with CRC-12, the CRC is bits 0 to 11 of the CRC value,
  142.    with the other two mentioned above, the CRC is all 16 bits.)
  143.  
  144.  
  145.    Here is a quick idea of what is being calculated ...
  146.  
  147.    The CRC is the residual from division of the data stream by
  148.    the CRC polynomial.  The data stream is also thought of as a
  149.    polynomial, with the highest order term being the lowest bit
  150.    of the first byte of the data stream and the lowest order term
  151.    of the polynomial being the high bit of the last byte of data.
  152.    The actual division is performed on the data stream polynomial
  153.    multiplied by X^y where y is the degree of the CRC polynomial.
  154.  
  155.  
  156.    CRC use ...
  157.  
  158.    The CRC is then appended to the end of the data stream.  When
  159.    the receiver gets the data stream, the CRC is again computed
  160.    and matched against the received CRC, if the two do not match
  161.    then an error has most likely occurred.
  162.  
  163.  
  164.  
  165.  
  166.  
  167. }
  168.  
  169.  
  170. {
  171.  
  172.    This work was prompted by a submission by David Kirschbaum,
  173.    who unknowingly submitted a program that contained an error.
  174.    I have not determined if what it computed has any reliable
  175.    error-detecting capabilities, only that it was an attempt to
  176.    compute a CRC, that really did not work.  The original code
  177.    is correctly used in the program KERMIT (Columbia University)
  178.    to compute the CRC-CCITT polynomial CRC.
  179.  
  180.  
  181.    My address is
  182.  
  183.    David Dantowitz
  184.    Digital Equipment Corporation
  185.    Dantowitz%eagle1.dec@decwrl
  186.  
  187.  
  188.    The views and ideas expressed here are my own and do not necessarily
  189.    reflect those of the Digital Equipment Corporation.
  190.  
  191.  
  192.    David Kirschbaum
  193.    Toad Hall
  194.    ABN.ISCAMS@USC-ISID.ARPA
  195. }
  196.  
  197. Procedure set_timer(count : Integer);
  198.  
  199. {
  200.     This routine sets the clock (timer) count-down value to
  201.     count.  The DOS value is 0 (this is the maximum value ...
  202.     it really means 65536).  This routine is used to obtain 
  203.     better resolution in timing.
  204.  
  205.     WARNING : The setting of count to too small a value will
  206.               HANG your system.  Please study interrupts in
  207.               real time systems before using this routine.
  208.  
  209.     WARNING : This routine was written to run on an IBM PC or
  210.               compatible.  Disable this routine when this 
  211.               program is run on other machines.
  212. }
  213.  
  214. Begin
  215.  
  216. inline($b0/$36/        { mov al,36        }
  217.        $e6/$43/        { out 43,al        }
  218.        $8b/$86/count/  { mov ax,bp[count] }
  219.        $e6/$40/        { out 40,al        }
  220.        $88/$e0/        { mov al,ah        }
  221.        $e6/$40);       { out 40,al        }
  222.  
  223. End;
  224.  
  225. Procedure simple_crc(b:byte);
  226.  
  227. {
  228.     This routine computes the CRC value bit by bit.  The initial value
  229.  is assumed to be in a global variable CRC_value and the global variable
  230.  POLY contains the representation of the polynomial be used.  The routine
  231.  is called for each byte.  The result is placed in the global CRC_value.
  232. }
  233.  
  234. Var
  235.     i : Integer;
  236.  
  237. Begin
  238. CRC_value := b xor CRC_value;
  239.  
  240. For i := 1 to 8 Do
  241.    Begin
  242.       If (CRC_value and 1) = 1
  243.          then CRC_value := (CRC_value shr 1) xor POLY
  244.          else CRC_value :=  CRC_value shr 1;
  245.    End;
  246.  
  247. End;
  248.  
  249. Procedure generate_table_16(POLY : Integer);
  250.  
  251. {
  252.     This routine computes the remainder values of 0 through 15 divided
  253.   by the polynomial represented by POLY.  These values are placed in a
  254.   table and used to compute the CRC of a block of data efficiently.
  255.  
  256.  
  257.     This implementation only permits polynomials up to degree 16.
  258. }
  259.  
  260.  
  261. Var
  262.    val, i, result : Integer;
  263.  
  264. Begin
  265. For val := 0 to 15 Do
  266.   Begin
  267.      result := val;
  268.      For i := 1 to 4 Do
  269.         Begin
  270.            If (result and 1) = 1
  271.               then result := (result shr 1) xor POLY
  272.               else result :=  result shr 1;
  273.         End;
  274.  
  275.      table_16[val] := result;
  276.   End
  277. End;
  278.  
  279.  
  280. Procedure generate_table_32(POLY : Integer);
  281.  
  282. {
  283.     This routine computes the remainder values of 0 through 15 divided
  284.   by the polynomial represented by POLY.  These values are placed in two
  285.   tables and used to compute the CRC of a block of data efficiently.
  286.  
  287.  
  288.     This implementation only permits polynomials up to degree 16.
  289. }
  290.  
  291.  
  292. Var
  293.    val, i, result, divide : Integer;
  294.  
  295. Begin
  296. {
  297.    Table_32a divides the number for eight bits (not four).
  298.    Note that Table_32b is identical to Table_16.
  299. }
  300.  
  301. For val := 0 to 15 Do
  302.   Begin
  303.      result := val;
  304.      For i := 1 to 4 Do
  305.         Begin
  306.            If (result and 1) = 1
  307.               then result := (result shr 1) xor POLY
  308.               else result :=  result shr 1;
  309.         End;
  310.  
  311.      table_32b[val] := result;
  312.   End;
  313.  
  314. For val := 0 to 15 Do
  315.   Begin
  316.      result := table_32b[val];
  317.      For i := 1 to 4 Do
  318.         Begin
  319.            If (result and 1) = 1
  320.               then result := (result shr 1) xor POLY
  321.               else result :=  result shr 1;
  322.         End;
  323.  
  324.      table_32a[val] := result;
  325.   End;
  326.  
  327. End;
  328.  
  329. Procedure generate_table_256(POLY : Integer);
  330.  
  331. {
  332.     This routine computes the remainder values of 0 through 255 divided
  333.   by the polynomial represented by POLY.  These values are placed in a
  334.   table and used to compute the CRC of a block of data efficiently.
  335.   More space is used, but the CRC computation will be faster.
  336.  
  337.  
  338.  
  339.     This implementation only permits polynomials up to degree 16.
  340. }
  341.  
  342.  
  343. Var
  344.    val, i, result, divide : Integer;
  345.  
  346. Begin
  347. For val := 0 to 255 Do
  348.   Begin
  349.      result := val;
  350.      For i := 1 to 8 Do
  351.         Begin
  352.            If (result and 1) = 1
  353.               then result := (result shr 1) xor POLY
  354.               else result :=  result shr 1;
  355.         End;
  356.  
  357.      table_256[val] := result;
  358.   End
  359. End;
  360.  
  361.  
  362. Procedure Compute_crc_16(next_byte : byte);
  363.  
  364. {
  365.    This routine calculates the CRC and stores the result in a global
  366.  variable CRC_value.  You must first initialize CRC_value to 0 or the
  367.  proper initial value for the CRC and then call this routine with
  368.  each byte.
  369.  
  370.     This routine uses table_16.
  371.  
  372. }
  373.  
  374. Begin
  375.  
  376. inline(
  377. $8b/$16/CRC_value/         {mov dx,CRC_value      }
  378. $32/$56/<next_byte/        {xor dl,next_byte[bp]    CRC = CRC XOR Next_byte  }
  379. $be/table_16/              {mov si,offset table_16  (table address)          }
  380. $30/$ff/                   {xor bh,bh               (bh <- 0)                }
  381.  
  382. $88/$d3/                   {mov bl,dl             }
  383. $80/$e3/$0f/               {and bl,0f             }
  384. $d0/$e3/                   {shl bl,1              }
  385. $b1/$04/                   {mov cl,4              }
  386. $d3/$ea/                   {shr dx,cl             }
  387. $33/$10/                   {xor dx,[bx+si]          CRC = (CRC shr 4) XOR
  388.                                                            table[CRC and 0F] }
  389.  
  390. $88/$d3/                   {mov bl,dl             }
  391. $80/$e3/$0f/               {and bl,0f             }
  392. $d0/$e3/                   {shl bl,1              }
  393. $b1/$04/                   {mov cl,4              }
  394. $d3/$ea/                   {shr dx,cl             }
  395. $33/$10/                   {xor dx,[bx+si]          CRC = (CRC shr 4) XOR
  396.                                                            table[CRC and 0F] }
  397.  
  398.  
  399. $89/$16/CRC_value);        {mov CRC_value,dx        Update CRC in memory     }
  400.  
  401. {  basic algorithm expressed above
  402.  
  403. temp := crc XOR next_byte;
  404.  
  405. For i := 1 to 2 Do
  406.    temp := (temp shr 4) XOR table [temp and $0F];
  407.  
  408. CRC_value := temp;
  409. }
  410. End;
  411.  
  412. Procedure Compute_crc_32(next_byte : byte);
  413. {
  414.    This is the algorithm used in KERMIT and attempted by the routine
  415.    DoCRC from Toad Hall.
  416.  
  417.    The code here completely new.  This routine uses table_32a and
  418.    table_32b.
  419. }
  420.  
  421. Begin
  422.  
  423. inline(
  424. $8b/$16/CRC_value/         {mov dx,CRC_value      }
  425.  
  426. $32/$56/<next_byte/        {xor dl,next_byte[bp]    CRC = CRC XOR Next_byte  }
  427.  
  428. { intermediate steps, see comments for overall effect }
  429.  
  430. $31/$db/                   {xor bx,bx               (bx <- 0)                }
  431. $86/$d3/                   {xchg bl,dl              (bx <- dx and 0FF)       }
  432. $86/$f2/                   {xchg dl,dh              (dx <- dx shr 8)         }
  433.  
  434. $88/$d8/                   {mov al,bl             }
  435. $80/$e3/$0f/               {and bl,0fh            }
  436. $d0/$e3/                   {shl bl,1                (bx <- bx+bx)            }
  437. $be/table_32a/             {mov si,offset table_32a (table address)          }
  438. $33/$10/                   {xor dx,[bx+si]        }
  439.  
  440. $88/$c3/                   {mov bl,al             }
  441. $80/$e3/$f0/               {and bl,0f0h           }
  442. $b1/$03/                   {mov cl,3              }
  443. $d2/$eb/                   {shr bl,cl             }
  444. $be/table_32b/             {mov si,offset table_32b (table address)          }
  445. $33/$10/                   {xor dx,[bx+si]        }
  446.  
  447. $89/$16/CRC_value);        {mov CRC_value,dx        Update CRC in memory     }
  448. End;
  449.  
  450.  
  451.  
  452. Procedure Compute_crc_256(next_byte : byte);
  453.  
  454. {
  455.    This routine calculates the CRC and stores the result in a global
  456.  variable CRC_value.  You must first initialize CRC_value to 0 or the
  457.  proper initial value for the CRC and then call this routine with
  458.  each byte.
  459.  
  460.    This routine uses table_256.
  461. }
  462.  
  463. Begin
  464.  
  465. inline(
  466. $8b/$16/CRC_value/         {mov dx,CRC_value      }
  467. $be/table_256/             {mov si,offset table_256 (table address)          }
  468.  
  469.  
  470. $32/$56/<next_byte/        {xor dl,next_byte[bp]    CRC = CRC XOR Next_byte  }
  471.  
  472. { intermediate steps, see comments for overall effect }
  473.  
  474. $31/$db/                   {xor bx,bx               (bx <- 0)                }
  475. $86/$d3/                   {xchg bl,dl              (bx <- dx and 0FF)       }
  476. $86/$f2/                   {xchg dl,dh              (dx <- dx shr 8)         }
  477. $d1/$e3/                   {shl bx,1                (bx <- bx+bx)            }
  478. $33/$10/                   {xor dx,[bx+si]          CRC = (CRC shr 8) XOR
  479.                                                            table[CRC and 0FF] }
  480.  
  481. $89/$16/CRC_value);        {mov CRC_value,dx        Update CRC in memory     }
  482.  
  483. {  basic algorithm expressed above
  484.  
  485. temp := crc XOR next_byte;
  486.  
  487. temp := (temp shr 8) XOR table_256 [temp and $FF];
  488.  
  489. CRC_value := temp;
  490. }
  491. End;
  492.  
  493. Function crc_string_16(Var s : Bytes; length, initial_crc : Integer) : Integer;
  494.  
  495. {
  496.      This routine computes the CRC value and returns it as the function
  497.   value.  The routine takes an array of Bytes, a length and an initial
  498.   value for the CRC.  The routine requires that a table of 16 values
  499.   be set up by a previous call to Generate_table_16.
  500.  
  501.      This routine uses table_16.
  502. }
  503.  
  504. Begin
  505.  
  506. inline(
  507.  
  508. $c4/$7e/<s/                {les di,s[bp]            (es:di points to array)  }
  509. $8b/$46/<initial_crc/      {mov ax,initial_crc[bp]  (initial CRC value)      }
  510. $8b/$56/<length/           {mov dx,length[bp]       (count)                  }
  511. $be/table_16/              {mov si,offset table_16  (table address)          }
  512. $30/$ff/                   {xor bh,bh               (bh <- 0)                }
  513.  
  514.  
  515. { next:  }
  516.  
  517. $26/$32/$05/               {xor al,es:[di]          CRC = CRC XOR next byte  }
  518. $47/                       {inc di                  (point to next byte)     }
  519.  
  520.  
  521. $88/$c3/                   {mov bl,al             }
  522. $80/$e3/$0f/               {and bl,0f             }
  523. $d0/$e3/                   {shl bl,1              }
  524. $b1/$04/                   {mov cl,4              }
  525. $d3/$e8/                   {shr ax,cl             }
  526. $33/$00/                   {xor ax,[bx+si]          CRC = (CRC shr 4) XOR
  527.                                                            table[CRC and 0F] }
  528.  
  529.  
  530. $88/$c3/                   {mov bl,al             }
  531. $80/$e3/$0f/               {and bl,0f             }
  532. $d0/$e3/                   {shl bl,1              }
  533. $b1/$04/                   {mov cl,4              }
  534. $d3/$e8/                   {shr ax,cl             }
  535. $33/$00/                   {xor ax,[bx+si]          CRC = (CRC shr 4) XOR
  536.                                                            table[CRC and 0F] }
  537.  
  538. $4a/                       {dec dx                  (count <- count -1)      }
  539. $75/$df/                   {jnz next               }
  540.  
  541. $89/$46/<s+4);             {mov s+4[bp],ax          (crc_string_16 := CRC)   }
  542.  
  543. {  basic algorithm expressed above
  544.  
  545.  
  546. temp := initial_crc;
  547.  
  548. For each byte Do
  549.  
  550. Begin
  551. temp := temp XOR next_byte;
  552.  
  553. For i := 1 to 2 Do
  554.    temp := (temp shr 4) XOR table [temp and $0F];
  555. End;
  556.  
  557. Crc_string_16 := temp;
  558. }
  559.  
  560. End;
  561.  
  562.  
  563. Function crc_string_256(Var s : Bytes; length, initial_crc : Integer) : Integer;
  564.  
  565. {
  566.      This routine computes the CRC value and returns it as the function
  567.   value.  The routine takes an array of Bytes, a length and an initial
  568.   value for the CRC.  The routine requires that a table of 256 values
  569.   be set up by a previous call to Generate_table_256.
  570.  
  571.       This routine uses table_256.
  572. }
  573.  
  574. Begin
  575.  
  576. inline(
  577.  
  578. $c4/$7e/<s/                {les di,s[bp]            (es:di points to array)  }
  579. $8b/$46/<initial_crc/      {mov ax,initial_crc[bp]  (initial CRC value)      }
  580. $8b/$4e/<length/           {mov cx,length[bp]       (count)                  }
  581. $be/table_256/             {mov si,offset table_256 (table address)          }
  582.  
  583.  
  584. { next:  }
  585.  
  586. $26/$32/$05/               {xor al,es:[di]          CRC = CRC XOR next byte  }
  587. $47/                       {inc di                  (point to next byte)     }
  588.  
  589. { intermediate steps, see comments for overall effect }
  590.  
  591. $31/$db/                   {xor bx,bx               (bx <- 0)                }
  592. $86/$d8/                   {xchg al,bl              (bx <- ax and 0FF)       }
  593. $86/$e0/                   {xchg al,ah              (ax <- ax shr 8)         }
  594. $d1/$e3/                   {shl bx,1                (bx <- bx+bx)            }
  595.  
  596. $33/$00/                   {xor ax,[bx+si]          CRC = (CRC shr 8) XOR
  597.                                                           table[CRC and 0FF] }
  598.  
  599. $e2/$f0/                   {loop next               (count <- count -1)      }
  600.  
  601. $89/$46/<s+4);             {mov s+4[bp],ax          (crc_string_256 := CRC)  }
  602.  
  603.  
  604. {  basic algorithm expressed above
  605.  
  606. crc := initial_crc
  607.  
  608. For each byte Do
  609. Begin
  610. crc := crc XOR next_byte;       
  611.  
  612. crc := (crc shr 8) XOR table_256 [crc and $FF];
  613. End;
  614.  
  615. crc_string_256 := crc;
  616. }
  617. End;
  618.  
  619.  
  620.  
  621. Begin
  622.  
  623. Writeln('Generating the data string, please wait ...');
  624. Writeln;
  625. Writeln;
  626.  
  627. Generate_table_16($8404);
  628. Generate_table_32($8404);
  629. Generate_table_256($8404);
  630.  
  631. For j := 1 to max Do
  632.    byte_string[j] := trunc(random*256);    { Create a data string }
  633.  
  634. length[1] := 512;
  635. length[2] := 1024;
  636. length[3] := 2048;
  637. length[4] := 4096;
  638. length[5] := 32767;
  639.  
  640. Writeln;
  641. Writeln('                      D a t a   S t r e a m   L e n g t h');
  642. Writeln;
  643. Write('             ');
  644.  
  645. For j := 1 to 5 Do
  646.    Write('  ', length[j]:8);
  647.  
  648. Writeln;
  649. Writeln;
  650.  
  651. Initial_clock := time;
  652.  
  653. Set_timer(5964);    { each tick = ~0.005 seconds }
  654.  
  655. {-----------------------------------------------------------------------------}
  656.  
  657. CRC_value := 0;
  658. POLY := $8404;
  659.  
  660. Write('No table          ');
  661.  
  662. For j := 1 to 5 Do
  663.    Begin
  664.    time := 0;
  665.    For i := 1 to length[j] Do
  666.       simple_crc(byte_string[i]);
  667.    stop := time;
  668.    Write(stop/200:5:2, '     ');
  669.    End;
  670.  
  671. Writeln('CRC = ', CRC_value);
  672.  
  673. {-----------------------------------------------------------------------------}
  674.  
  675. CRC_value := 0;
  676.  
  677. Write('Nybble table      ');
  678.  
  679. For j := 1 to 5 Do
  680.    Begin
  681.    time := 0;
  682.    For i := 1 to length[j] Do
  683.       compute_crc_16(byte_string[i]);
  684.    stop := time;
  685.    Write(stop/200:5:2, '     ');
  686.    End;
  687.  
  688. Writeln('CRC = ', CRC_value);
  689.  
  690. {-----------------------------------------------------------------------------}
  691.  
  692. CRC_value := 0;
  693.  
  694. Write('Two Nybble tables ');
  695.  
  696. For j := 1 to 5 Do
  697.    Begin
  698.    time := 0;
  699.    For i := 1 to length[j] Do
  700.       compute_crc_32(byte_string[i]);
  701.    stop := time;
  702.    Write(stop/200:5:2, '     ');
  703.    End;
  704.  
  705. Writeln('CRC = ', CRC_value);
  706.  
  707. {-----------------------------------------------------------------------------}
  708.  
  709. CRC_value := 0;
  710.  
  711. Write('Byte table        ');
  712.  
  713. For j := 1 to 5 Do
  714.    Begin
  715.    time := 0;
  716.    For i := 1 to length[j] Do
  717.       compute_crc_256(byte_string[i]);
  718.    stop := time;
  719.    Write(stop/200:5:2, '     ');
  720.    End;
  721.  
  722. Writeln('CRC = ', CRC_value);
  723.  
  724. {-----------------------------------------------------------------------------}
  725.  
  726. CRC_value := 0;
  727.  
  728. Write('Nybble string     ');
  729.  
  730. For j := 1 to 5 Do
  731.    Begin
  732.    time := 0;
  733.    CRC_value := crc_string_16(byte_string, length[j], CRC_value);
  734.    stop := time;
  735.    Write(stop/200:5:2, '     ');
  736.    End;
  737.  
  738. Writeln('CRC = ', CRC_value);
  739.  
  740. {-----------------------------------------------------------------------------}
  741.  
  742. CRC_value := 0;
  743.  
  744. Write('Byte string       ');    
  745.  
  746. For j := 1 to 5 Do
  747.    Begin
  748.    time := 0;
  749.    CRC_value := crc_string_256(byte_string, length[j], CRC_value);
  750.    stop := time;
  751.    Write(stop/200:5:2, '     ');
  752.    End;
  753.  
  754. Writeln('CRC = ', CRC_value);
  755.  
  756. {-----------------------------------------------------------------------------}
  757.  
  758. set_timer(0);   { restore the clock to the normal DOS value }
  759.  
  760. time := initial_clock;   { we may have lost a few minutes ... }
  761.  
  762. End.
  763.