home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / crc / crc_pas / crctime.pas next >
Encoding:
Pascal/Delphi Source File  |  1994-04-11  |  16.0 KB  |  422 lines

  1.       { file crctime.pas, 85/9/18/tfr (from 9/15, 7/13, 6/27-26,
  2.                           showtime.pas 3/23, 1/4, 84/12/25
  3.                           and showkeys 12/12-11, 11/17
  4.                           and strinkey.pas, 11/17) }
  5.       { compute crc execution times }
  6.       { Copyright (c) 1984, 1985, T.F. Ritter; All Rights Reserved }
  7.       { Please feel free to copy and use the CRC routines, but . . . }
  8.       {    do include the name of the CRC programmer when you do. }
  9.       { The CRC programmer is Terry Ritter. }
  10.       { AIMS: }
  11.       { 1. Display a number of different CRC-CCITT implementations. }
  12.       { 2. Verify identical results. }
  13.       { 3. Collect and display time statistics on each routine. }
  14.       PROGRAM showtime;
  15.       { minimum overhead for speed tests }
  16.       {$R-}  { Range Checks OFF }
  17.       {$C-}  { Ctrl-C Checking OFF }
  18.       PROCEDURE ownership;
  19.          BEGIN
  20.          WRITE( con,
  21. ^M^J, 'CRCTIME, 85/9/18',
  22. ^M^J, 'Execution times for various CRC implementations.',
  23. ^M^J, 'Copyright (c) 1985, T.F. Ritter; All Rights Reserved.',
  24. ^M^J     );
  25.          END;
  26.       TYPE
  27.          regs = RECORD
  28.                 ax,bx,cx,dx,bp,si,di,ds,es,flags: INTEGER;
  29.                 END;
  30.       PROCEDURE bdosch( ch: CHAR );
  31.          { direct console output through MSDOS }
  32.          { allows Ctrl-P printer toggle }
  33.          { also skips Ctrl-C break test }
  34.          VAR
  35.             r: regs;
  36.          BEGIN
  37.          r.ax := $0200;
  38.          r.dx := ORD(ch);
  39.          MsDos( r );
  40.          END;
  41.       { start of time operations }
  42.       TYPE
  43.          timearty = ARRAY[0..3] of INTEGER; {originally had yr, dy}
  44.       PROCEDURE readhms( VAR dt: timearty );
  45.          { Hi(dt[2]) = hrs (0 - 23), Lo(dt[2]) = mins (0 - 59) }
  46.          { Hi(dt[3]) = secs (0 - 59), Lo(dt[3]) = msecs (0 - 99) }
  47.          VAR
  48.             r: regs;
  49.          BEGIN
  50.          r.ax := $2c00;
  51.          MsDos( r );
  52.          dt[2] := r.cx;
  53.          dt[3] := r.dx;
  54.          END; { rddtti }
  55.       FUNCTION timetorealsecs( x: timearty ): REAL;
  56.          BEGIN
  57.          timetorealsecs := (Hi(x[2]) * 3600.0)  +  (Lo(x[2]) * 60.0)  +
  58.                             Hi(x[3])  +  (Lo(x[3]) / 100.0);
  59.          END;
  60.       FUNCTION timedif( a, b: timearty ): REAL;
  61.          BEGIN
  62.          timedif := timetorealsecs( b ) - timetorealsecs( a );
  63.          END;
  64.       { start of CRC stuff }
  65.       { byte crc in Turbo Pascal }
  66.       { for MSDOS }
  67.       { METHOD 1:  Pascal Bit-By-Bit }
  68.       { bit manipulation in a high-level-language }
  69.       { simulation of "longhand" division }
  70.       { mostly for verification of other methods }
  71.       PROCEDURE crcittb( VAR a: INTEGER; databit: BOOLEAN);
  72.          { single bit computation; simulate polydiv hardware }
  73.          { other Pascals can replace "a SHL 1" with "a + a" }
  74.          BEGIN
  75.          IF databit = (a < 0) THEN
  76.             a := a Shl 1
  77.          ELSE
  78.             a := (a Shl 1) XOR $1021;  { CRC-CCITT }
  79.          END; { crcittb }
  80.       PROCEDURE crcittby( VAR aa: INTEGER; d: INTEGER );
  81.          { whole byte computation }
  82.          VAR
  83.             i: INTEGER;
  84.          BEGIN
  85.          d := d Shl 7;
  86.          FOR i := 7 DOWNTO 0 DO
  87.             BEGIN
  88.             d := d Shl 1;
  89.             crcittb( aa, (d < 0) );
  90.             END;
  91.          END; { crcittby }
  92.       { METHOD 2: Pascal Fast Bit-By-Bit }
  93.       { eliminates procedure-call overhead in the loop }
  94.       { similar to most XMODEM crc implementations}
  95.       PROCEDURE crcfbbb( VAR aa: INTEGER; d: INTEGER );
  96.          { fast bit-by-bit whole byte computation }
  97.          VAR
  98.             i: INTEGER;
  99.          BEGIN
  100.          d := d Shl 7;
  101.          FOR i := 7 DOWNTO 0 DO
  102.             BEGIN
  103.             d := d Shl 1;
  104.             IF ((d  XOR aa) < 0) THEN
  105.                aa := (aa Shl 1) XOR $1021
  106.             ELSE
  107.                aa := aa Shl 1;
  108.             END;
  109.          END; { crcfbbb }
  110.       { METHOD 3: Pascal Byte }
  111.       { process the data byte without loops }
  112.       { transportable within Turbo Pascal, and fairly fast }
  113.       { may be slower in Pascals without bit-shifting operations }
  114.       PROCEDURE crcitta( VAR dx: INTEGER; data: INTEGER);
  115.          { dx := crcTransform( dx; data ) }
  116.          { polynomial = $11021 }
  117.          { FOR OTHER PASCALS: }
  118.          {      Generate a Swap function "swap( x: INTEGER ): INTEGER" }
  119.          { probably "swap := (x * 256) + (x DIV 256) would work" }
  120.          { Lo(x) = x AND $00ff = x AND 255 }
  121.          { x Shr 4 = x DIV 16 }
  122.          { x Shl 4 = x * 16 }
  123.          { x Shl 5 = x * 32 }
  124.          BEGIN { crcitta }
  125.          dx := Swap( dx ) XOR data;
  126.          dx := dx XOR ( Lo(dx) Shr 4 );
  127.          dx := dx XOR (Swap(Lo(dx)) Shl 4) XOR (Lo(dx) Shl 5);
  128.          END; { crcitta }
  129.       { METHOD 4: Pascal Table }
  130.       { pull changes from table, indexed by composite value }
  131.       { still faster, but requires the table, and filling the table }
  132.       { may be even faster, relatively, in another Pascal }
  133.       { a slower routine is fine to fill the table }
  134.       VAR
  135.          crctab:  ARRAY[0..255] of INTEGER;
  136.       PROCEDURE crctablu( VAR crcreg: INTEGER; data: INTEGER);
  137.          BEGIN
  138.          crcreg := Swap(crcreg) XOR data;
  139.          crcreg := (crcreg AND $ff00) XOR crctab[ Lo(crcreg) ];
  140.          END;
  141.       PROCEDURE initctab;
  142.          { use method 3 to init the table }
  143.          VAR
  144.             i: INTEGER;
  145.          BEGIN
  146.          FOR i := 0 TO 255 DO
  147.             BEGIN
  148.             crctab[i] := 0;
  149.             crcitta( crctab[i], i );
  150.             END;
  151.          END; {initctab}
  152.       { METHOD 5: Machine Code Byte }
  153.       { method 3 in "Inline" machine code (MSDOS) }
  154.       { typically hidden away in an "Include" file }
  155.       { other Pascals may need to modify the stack interface }
  156.       PROCEDURE mcrcitt1( VAR dx: INTEGER; data: INTEGER );
  157.          { a := crcTransform( dx; data ) }
  158.          { for MSDOS }
  159.          { polynomial = $11021 }
  160.          BEGIN { mcrcitt1 }
  161.          INLINE (
  162.                    $c4/$7e/<dx/   {  es:di := [bp +"dx"]   }
  163.                    $26/$8b/$05/   {  ax := [es:di]         }
  164.          { dx := SWAP(dx) XOR data; }
  165.                    $86/$e0/       {  ah <=> al             }
  166.                    $33/$46/<data/ {  ax := ax XOR [bp + "data"] }
  167.                    $89/$c2/       {  dx := ax              }
  168.          { dx := dx XOR ( LO(dx) SHR 4 ); }
  169.                    $d0/$e8/       {  al := al SHR 1        }
  170.                    $d0/$e8/       {  al := al SHR 1        }
  171.                    $d0/$e8/       {  al := al SHR 1        }
  172.                    $d0/$e8/       {  al := al SHR 1        }
  173.                    $32/$d0/       {  dl := dl XOR al       }
  174.          { dx := dx XOR ( (SWAP( LO(dx) ) SHL 4 ); }
  175.                    $88/$d4/       {  ah := dl              }
  176.                    $d0/$e4/       {  ah := ah SHL 1        }
  177.                    $d0/$e4/       {  ah := ah SHL 1        }
  178.                    $d0/$e4/       {  ah := ah SHL 1        }
  179.                    $d0/$e4/       {  ah := ah SHL 1        }
  180.                    $32/$f4/       {  dh := dh XOR ah       }
  181.          { dx := dx XOR ( ( LO(dx) ) SHL 5 ); }
  182.                    $88/$d0/       {  al := dl              }
  183.                    $b4/$00/       {  ah := 0               }
  184.                    $d1/$e0/       {  ax := ax SHL 1        }
  185.                    $d1/$e0/       {  ax := ax SHL 1        }
  186.                    $d1/$e0/       {  ax := ax SHL 1        }
  187.                    $d1/$e0/       {  ax := ax SHL 1        }
  188.                    $d1/$e0/       {  ax := ax SHL 1        }
  189.                    $33/$d0/       {  dx := dx XOR ax       }
  190.                    $26/$89/$15    {  es:[di] := dx         } );
  191.          END; { mcrcitt1 }
  192.       { METHOD 6: Machine Code Table }
  193.       { here the stack parameter interface becomes significant }
  194.       { note the exchange notation "x :=: y" in the comments }
  195.       PROCEDURE mcrcitt3( VAR dx: INTEGER; data: INTEGER );
  196.          { a := crcTransform( dx; data ) }
  197.          { for MSDOS }
  198.          { polynomial = $11021 }
  199.          BEGIN { mcrcitt3 }
  200.          INLINE (
  201.                    $c4/$7e/<dx/   {  es:di := [bp +"dx"]   }
  202.                    $26/$8b/$15/   {  dx := [es:di]         }
  203.          { dx := Swap(dx) XOR data; }
  204.                    $86/$d6/       {  dh :=: dl             }
  205.                    $33/$56/<data/ {  dx := dx XOR [bp + "data"] }
  206.          { bx := Lo(dx) SHL 1;  dl := 0; }
  207.                    $31/$db/       {  bx := bx XOR bx       }
  208.                    $86/$d3/       {  bl :=: dl             }
  209.                    $d1/$e3/       {  bx := bx SHL 1        }
  210.          { dx := dx XOR crctab[ bx ]; }
  211.                    $33/$97/>crctab/  {  dx := dx XOR [bx + "crctab"] }
  212.                    $26/$89/$15    {  [es:di] := dx         } );
  213.          END; { mcrcitt3 }
  214.       { start of validation testing }
  215.       PROCEDURE fultest( beg: INTEGER );
  216.          CONST
  217.             maxpass = 5;
  218.          TYPE
  219.             st40 = STRING[40];
  220.             passtype = ARRAY[ 1..maxpass ] of INTEGER;
  221.          VAR
  222.             adi, pass: INTEGER;
  223.             adr, adt: passtype;
  224.          PROCEDURE overall( VAR a: passtype; t: INTEGER );
  225.             VAR
  226.                x, en, loc: INTEGER;
  227.                data: BYTE;
  228.             BEGIN
  229.             FOR pass := 1 to maxpass DO
  230.                BEGIN
  231.                x := adi;
  232.                   CASE pass OF
  233.                   1: en := beg;
  234.                   2: en := beg + 1;
  235.                   3: en := beg + 127;
  236.                   4: en := beg + 511;
  237.                   5: en := beg + 81;
  238.                   END;
  239.                FOR loc := beg TO en DO
  240.                   BEGIN
  241.                   { a source of data "random" enough for our purposes }
  242.                   {   is available in the program code area }
  243.                   data := MEM[ Cseg: loc ];
  244.                      CASE t OF
  245.                      1: crcittby( x, data );
  246.                      2: crcfbbb( x, data );
  247.                      3: crcitta( x, data );
  248.                      4: crctablu( x, data );
  249.                      5: mcrcitt1( x, data );
  250.                      6: mcrcitt3( x, data );
  251.                      END; {case}
  252.                   END;
  253.                a[pass] := x;
  254.                END;
  255.             END; {overall}
  256.       PROCEDURE pbin( value: INTEGER );
  257.          VAR
  258.             i: INTEGER;
  259.          BEGIN
  260.          FOR i := 15 DOWNTO 0 DO
  261.             BEGIN
  262.             IF value < 0 THEN
  263.                WRITE( '1' )
  264.             ELSE
  265.                WRITE( '0' );
  266.             value := value SHL 1;
  267.             END;
  268.          END; {pbin}
  269.          PROCEDURE showres( s: st40 );
  270.             VAR
  271.                errfound: BOOLEAN;
  272.             BEGIN
  273.             errfound := FALSE;
  274.             WRITE( ^M^J'   ', s );
  275.             FOR pass := 1 TO maxpass DO
  276.                IF (adt[pass] <> adr[pass]) THEN
  277.                   BEGIN
  278.                   errfound := TRUE;
  279.                   WRITE( ^M^J'Pass ', pass, ': CRC error.' );
  280.                   WRITE( ^M^J, 'Reference:  '); pbin( adr[pass] );
  281.                   WRITE( ^M^J, 'Under Test: '); pbin( adt[pass] );
  282.                   END;
  283.             IF NOT errfound THEN
  284.                   WRITE( ': No error.' );
  285.             END; {showres}
  286.          BEGIN {fultest}
  287.          WRITE( ^M^J^J'BEGIN Validation Testing.' );
  288.          adi := -1;
  289.          initctab;
  290.          overall( adr, 1 );
  291.          WRITE( ^M^J'   Reference = crcittby (Pascal Bit-By-Bit).' );
  292.          overall( adt, 2 );
  293.          showres( 'crcfbbb (Pascal Fast Bit-By-Bit)' );
  294.          overall( adt, 3 );
  295.          showres( 'crcitta (Pascal Byte)' );
  296.          overall( adt, 4 );
  297.          showres( 'crctablu (Pascal Table)' );
  298.          overall( adt, 5 );
  299.          showres( 'mcrcitt1 (Machine Code Byte)' );
  300.          overall( adt, 6 );
  301.          showres( 'mcrcitt3 (Machine Code Table)' );
  302.          WRITELN( ^M^J'END Validation Testing.' );
  303.          END;  { fultest }
  304.       { start of timing }
  305.       PROCEDURE timetest( loops: INTEGER );
  306.          { organize the time testing of various routines }
  307.          VAR
  308.             a, b: timearty;
  309.             i, x: INTEGER;
  310.             by: BYTE;
  311.             empty: REAL;  { time for empty loops }
  312.             calltime: REAL;  { time for loops and empty procedure }
  313.          PROCEDURE crcmt( VAR dx: INTEGER; data: INTEGER);
  314.             BEGIN
  315.             END;
  316.          PROCEDURE showtimedif( a, b: timearty; c: INTEGER );
  317.             { display a line of time results }
  318.             VAR
  319.                dif, Noloop, NoloopNocall: REAL;
  320.             BEGIN
  321.             dif := timedif( a, b );
  322.             Noloop := dif - empty;
  323.             NoloopNocall := dif - calltime;
  324.             WRITE(
  325. Noloop:7:3, '  ', NoloopNocall:7:3,'       ',
  326. Noloop * (1000.0 / c):7:3, '  ', NoloopNocall * (1000.0 / c):7:3  );
  327.             END; {showtimedif}
  328.          BEGIN {timetest}
  329.          calltime := 0.0;  {the global}
  330.          by := $a5;  {your typical data byte}
  331.          WRITELN(
  332. ^M^J^J'Turbo Pascal runs CRC-CCITT on 8088 under Bare MSDOS',
  333.   ^M^J'   FOR ', loops,' OPERATIONS; 7.16 MHz CLOCK  (multiply by 1.5 for 4.77 MHz)' );
  334.          WRITE( ^M^J'Empty loop:  ' );
  335.          readhms( a );
  336.          FOR i := 1 TO loops DO
  337.              ;
  338.          readhms( b );
  339.          empty := timedif( a, b);  {the global}
  340.          WRITE( empty:5:3, ' secs' );
  341.          WRITE( ^M^J'Empty procedure in loop:  ' );
  342.          readhms( a );
  343.          FOR i := 1 TO loops DO
  344.             crcmt( x, by );
  345.          readhms( b );
  346.          calltime := timedif( a, b ); {another global}
  347.          WRITE( calltime:5:3, ' secs' );
  348.          WRITE( ^M^J'   (procedure overhead alone = ',
  349.                  (calltime - empty) * (1000.0 / loops):6:3,
  350.                  ' msec each)' );
  351.          WRITELN(
  352. ^M^J^J'                      ', loops:5, ' Uses (secs)        1 Use (msec)',
  353.   ^M^J'                     Procedure   In Line    Procedure   In Line' );
  354.          WRITE(
  355. ^M^J'Pascal Bit-by-Bit:    ' );
  356.          readhms( a );
  357.          FOR i := 1 TO loops DO
  358.             crcittby( x, by );
  359.          readhms( b );
  360.          showtimedif( a, b, loops );
  361.          WRITE(
  362. ^M^J'Pascal Fast B-B-B:    ' );
  363.          readhms( a );
  364.          FOR i := 1 TO loops DO
  365.             crcfbbb( x, by );
  366.          readhms( b );
  367.          showtimedif( a, b, loops );
  368.          WRITE(
  369. ^M^J'Pascal Byte:          ' );
  370.          readhms( a );
  371.          FOR i := 1 TO loops DO
  372.             crcitta( x, by );
  373.          readhms( b );
  374.          showtimedif( a, b, loops );
  375.          WRITE(
  376. ^M^J'Pascal Table:         ' );
  377.          readhms( a );
  378.          FOR i := 1 TO loops DO
  379.             crctablu( x, by );
  380.          readhms( b );
  381.          showtimedif( a, b, loops );
  382.          WRITE(
  383. ^M^J'Machine Code Byte:    ' );
  384.          readhms( a );
  385.          FOR i := 1 TO loops DO
  386.             mcrcitt1( x, by );
  387.          readhms( b );
  388.          showtimedif( a, b, loops );
  389.          WRITE(
  390. ^M^J'Machine Code Table:   ' );
  391.          readhms( a );
  392.          FOR i := 1 TO loops DO
  393.             mcrcitt3( x, by );
  394.          readhms( b );
  395.          showtimedif( a, b, loops );
  396.          WRITELN;
  397.          END; {timetest}
  398.       PROCEDURE datatimes;
  399.          { data character times, for comparison }
  400.          CONST
  401.             rates: ARRAY[1..7] of INTEGER =
  402.                    ( 12, 24, 48, 96, 192, 384, 576 );
  403.          VAR i: INTEGER;
  404.          BEGIN
  405.          WRITELN( ^M^J^J'Character Times for Various Bit Rates: ' );
  406.          WRITE( ^M^J'   bits/sec     char/sec    msec/char');
  407.          FOR i := 1 TO 7 DO
  408.             WRITE( ^M^J, '':4, (100.0 * rates[i]):5:0, '':8,
  409.                                (10.0 * rates[i]):5:0, '':8,
  410.                                (100.0 / rates[i]):5:3 );
  411.          WRITELN;
  412.          END; {datatimes}
  413.       BEGIN { main: crctime }
  414.       WRITELN;
  415.       ConOutPtr := OFS( bdosch );  {output through MSDOS}
  416.       ownership;
  417.       fultest( 100 );
  418.       timetest( 10000 );
  419.       datatimes;
  420.       END.
  421.       { end file crctime.pas }
  422.