home *** CD-ROM | disk | FTP | other *** search
- { file crctime.pas, 85/9/18/tfr (from 9/15, 7/13, 6/27-26,
- showtime.pas 3/23, 1/4, 84/12/25
- and showkeys 12/12-11, 11/17
- and strinkey.pas, 11/17) }
- { compute crc execution times }
- { Copyright (c) 1984, 1985, T.F. Ritter; All Rights Reserved }
- { Please feel free to copy and use the CRC routines, but . . . }
- { do include the name of the CRC programmer when you do. }
- { The CRC programmer is Terry Ritter. }
- { AIMS: }
- { 1. Display a number of different CRC-CCITT implementations. }
- { 2. Verify identical results. }
- { 3. Collect and display time statistics on each routine. }
- PROGRAM showtime;
- { minimum overhead for speed tests }
- {$R-} { Range Checks OFF }
- {$C-} { Ctrl-C Checking OFF }
- PROCEDURE ownership;
- BEGIN
- WRITE( con,
- ^M^J, 'CRCTIME, 85/9/18',
- ^M^J, 'Execution times for various CRC implementations.',
- ^M^J, 'Copyright (c) 1985, T.F. Ritter; All Rights Reserved.',
- ^M^J );
- END;
- TYPE
- regs = RECORD
- ax,bx,cx,dx,bp,si,di,ds,es,flags: INTEGER;
- END;
- PROCEDURE bdosch( ch: CHAR );
- { direct console output through MSDOS }
- { allows Ctrl-P printer toggle }
- { also skips Ctrl-C break test }
- VAR
- r: regs;
- BEGIN
- r.ax := $0200;
- r.dx := ORD(ch);
- MsDos( r );
- END;
- { start of time operations }
- TYPE
- timearty = ARRAY[0..3] of INTEGER; {originally had yr, dy}
- PROCEDURE readhms( VAR dt: timearty );
- { Hi(dt[2]) = hrs (0 - 23), Lo(dt[2]) = mins (0 - 59) }
- { Hi(dt[3]) = secs (0 - 59), Lo(dt[3]) = msecs (0 - 99) }
- VAR
- r: regs;
- BEGIN
- r.ax := $2c00;
- MsDos( r );
- dt[2] := r.cx;
- dt[3] := r.dx;
- END; { rddtti }
- FUNCTION timetorealsecs( x: timearty ): REAL;
- BEGIN
- timetorealsecs := (Hi(x[2]) * 3600.0) + (Lo(x[2]) * 60.0) +
- Hi(x[3]) + (Lo(x[3]) / 100.0);
- END;
- FUNCTION timedif( a, b: timearty ): REAL;
- BEGIN
- timedif := timetorealsecs( b ) - timetorealsecs( a );
- END;
- { start of CRC stuff }
- { byte crc in Turbo Pascal }
- { for MSDOS }
- { METHOD 1: Pascal Bit-By-Bit }
- { bit manipulation in a high-level-language }
- { simulation of "longhand" division }
- { mostly for verification of other methods }
- PROCEDURE crcittb( VAR a: INTEGER; databit: BOOLEAN);
- { single bit computation; simulate polydiv hardware }
- { other Pascals can replace "a SHL 1" with "a + a" }
- BEGIN
- IF databit = (a < 0) THEN
- a := a Shl 1
- ELSE
- a := (a Shl 1) XOR $1021; { CRC-CCITT }
- END; { crcittb }
- PROCEDURE crcittby( VAR aa: INTEGER; d: INTEGER );
- { whole byte computation }
- VAR
- i: INTEGER;
- BEGIN
- d := d Shl 7;
- FOR i := 7 DOWNTO 0 DO
- BEGIN
- d := d Shl 1;
- crcittb( aa, (d < 0) );
- END;
- END; { crcittby }
- { METHOD 2: Pascal Fast Bit-By-Bit }
- { eliminates procedure-call overhead in the loop }
- { similar to most XMODEM crc implementations}
- PROCEDURE crcfbbb( VAR aa: INTEGER; d: INTEGER );
- { fast bit-by-bit whole byte computation }
- VAR
- i: INTEGER;
- BEGIN
- d := d Shl 7;
- FOR i := 7 DOWNTO 0 DO
- BEGIN
- d := d Shl 1;
- IF ((d XOR aa) < 0) THEN
- aa := (aa Shl 1) XOR $1021
- ELSE
- aa := aa Shl 1;
- END;
- END; { crcfbbb }
- { METHOD 3: Pascal Byte }
- { process the data byte without loops }
- { transportable within Turbo Pascal, and fairly fast }
- { may be slower in Pascals without bit-shifting operations }
- PROCEDURE crcitta( VAR dx: INTEGER; data: INTEGER);
- { dx := crcTransform( dx; data ) }
- { polynomial = $11021 }
- { FOR OTHER PASCALS: }
- { Generate a Swap function "swap( x: INTEGER ): INTEGER" }
- { probably "swap := (x * 256) + (x DIV 256) would work" }
- { Lo(x) = x AND $00ff = x AND 255 }
- { x Shr 4 = x DIV 16 }
- { x Shl 4 = x * 16 }
- { x Shl 5 = x * 32 }
- BEGIN { crcitta }
- dx := Swap( dx ) XOR data;
- dx := dx XOR ( Lo(dx) Shr 4 );
- dx := dx XOR (Swap(Lo(dx)) Shl 4) XOR (Lo(dx) Shl 5);
- END; { crcitta }
- { METHOD 4: Pascal Table }
- { pull changes from table, indexed by composite value }
- { still faster, but requires the table, and filling the table }
- { may be even faster, relatively, in another Pascal }
- { a slower routine is fine to fill the table }
- VAR
- crctab: ARRAY[0..255] of INTEGER;
- PROCEDURE crctablu( VAR crcreg: INTEGER; data: INTEGER);
- BEGIN
- crcreg := Swap(crcreg) XOR data;
- crcreg := (crcreg AND $ff00) XOR crctab[ Lo(crcreg) ];
- END;
- PROCEDURE initctab;
- { use method 3 to init the table }
- VAR
- i: INTEGER;
- BEGIN
- FOR i := 0 TO 255 DO
- BEGIN
- crctab[i] := 0;
- crcitta( crctab[i], i );
- END;
- END; {initctab}
- { METHOD 5: Machine Code Byte }
- { method 3 in "Inline" machine code (MSDOS) }
- { typically hidden away in an "Include" file }
- { other Pascals may need to modify the stack interface }
- PROCEDURE mcrcitt1( VAR dx: INTEGER; data: INTEGER );
- { a := crcTransform( dx; data ) }
- { for MSDOS }
- { polynomial = $11021 }
- BEGIN { mcrcitt1 }
- INLINE (
- $c4/$7e/<dx/ { es:di := [bp +"dx"] }
- $26/$8b/$05/ { ax := [es:di] }
- { dx := SWAP(dx) XOR data; }
- $86/$e0/ { ah <=> al }
- $33/$46/<data/ { ax := ax XOR [bp + "data"] }
- $89/$c2/ { dx := ax }
- { dx := dx XOR ( LO(dx) SHR 4 ); }
- $d0/$e8/ { al := al SHR 1 }
- $d0/$e8/ { al := al SHR 1 }
- $d0/$e8/ { al := al SHR 1 }
- $d0/$e8/ { al := al SHR 1 }
- $32/$d0/ { dl := dl XOR al }
- { dx := dx XOR ( (SWAP( LO(dx) ) SHL 4 ); }
- $88/$d4/ { ah := dl }
- $d0/$e4/ { ah := ah SHL 1 }
- $d0/$e4/ { ah := ah SHL 1 }
- $d0/$e4/ { ah := ah SHL 1 }
- $d0/$e4/ { ah := ah SHL 1 }
- $32/$f4/ { dh := dh XOR ah }
- { dx := dx XOR ( ( LO(dx) ) SHL 5 ); }
- $88/$d0/ { al := dl }
- $b4/$00/ { ah := 0 }
- $d1/$e0/ { ax := ax SHL 1 }
- $d1/$e0/ { ax := ax SHL 1 }
- $d1/$e0/ { ax := ax SHL 1 }
- $d1/$e0/ { ax := ax SHL 1 }
- $d1/$e0/ { ax := ax SHL 1 }
- $33/$d0/ { dx := dx XOR ax }
- $26/$89/$15 { es:[di] := dx } );
- END; { mcrcitt1 }
- { METHOD 6: Machine Code Table }
- { here the stack parameter interface becomes significant }
- { note the exchange notation "x :=: y" in the comments }
- PROCEDURE mcrcitt3( VAR dx: INTEGER; data: INTEGER );
- { a := crcTransform( dx; data ) }
- { for MSDOS }
- { polynomial = $11021 }
- BEGIN { mcrcitt3 }
- INLINE (
- $c4/$7e/<dx/ { es:di := [bp +"dx"] }
- $26/$8b/$15/ { dx := [es:di] }
- { dx := Swap(dx) XOR data; }
- $86/$d6/ { dh :=: dl }
- $33/$56/<data/ { dx := dx XOR [bp + "data"] }
- { bx := Lo(dx) SHL 1; dl := 0; }
- $31/$db/ { bx := bx XOR bx }
- $86/$d3/ { bl :=: dl }
- $d1/$e3/ { bx := bx SHL 1 }
- { dx := dx XOR crctab[ bx ]; }
- $33/$97/>crctab/ { dx := dx XOR [bx + "crctab"] }
- $26/$89/$15 { [es:di] := dx } );
- END; { mcrcitt3 }
- { start of validation testing }
- PROCEDURE fultest( beg: INTEGER );
- CONST
- maxpass = 5;
- TYPE
- st40 = STRING[40];
- passtype = ARRAY[ 1..maxpass ] of INTEGER;
- VAR
- adi, pass: INTEGER;
- adr, adt: passtype;
- PROCEDURE overall( VAR a: passtype; t: INTEGER );
- VAR
- x, en, loc: INTEGER;
- data: BYTE;
- BEGIN
- FOR pass := 1 to maxpass DO
- BEGIN
- x := adi;
- CASE pass OF
- 1: en := beg;
- 2: en := beg + 1;
- 3: en := beg + 127;
- 4: en := beg + 511;
- 5: en := beg + 81;
- END;
- FOR loc := beg TO en DO
- BEGIN
- { a source of data "random" enough for our purposes }
- { is available in the program code area }
- data := MEM[ Cseg: loc ];
- CASE t OF
- 1: crcittby( x, data );
- 2: crcfbbb( x, data );
- 3: crcitta( x, data );
- 4: crctablu( x, data );
- 5: mcrcitt1( x, data );
- 6: mcrcitt3( x, data );
- END; {case}
- END;
- a[pass] := x;
- END;
- END; {overall}
- PROCEDURE pbin( value: INTEGER );
- VAR
- i: INTEGER;
- BEGIN
- FOR i := 15 DOWNTO 0 DO
- BEGIN
- IF value < 0 THEN
- WRITE( '1' )
- ELSE
- WRITE( '0' );
- value := value SHL 1;
- END;
- END; {pbin}
- PROCEDURE showres( s: st40 );
- VAR
- errfound: BOOLEAN;
- BEGIN
- errfound := FALSE;
- WRITE( ^M^J' ', s );
- FOR pass := 1 TO maxpass DO
- IF (adt[pass] <> adr[pass]) THEN
- BEGIN
- errfound := TRUE;
- WRITE( ^M^J'Pass ', pass, ': CRC error.' );
- WRITE( ^M^J, 'Reference: '); pbin( adr[pass] );
- WRITE( ^M^J, 'Under Test: '); pbin( adt[pass] );
- END;
- IF NOT errfound THEN
- WRITE( ': No error.' );
- END; {showres}
- BEGIN {fultest}
- WRITE( ^M^J^J'BEGIN Validation Testing.' );
- adi := -1;
- initctab;
- overall( adr, 1 );
- WRITE( ^M^J' Reference = crcittby (Pascal Bit-By-Bit).' );
- overall( adt, 2 );
- showres( 'crcfbbb (Pascal Fast Bit-By-Bit)' );
- overall( adt, 3 );
- showres( 'crcitta (Pascal Byte)' );
- overall( adt, 4 );
- showres( 'crctablu (Pascal Table)' );
- overall( adt, 5 );
- showres( 'mcrcitt1 (Machine Code Byte)' );
- overall( adt, 6 );
- showres( 'mcrcitt3 (Machine Code Table)' );
- WRITELN( ^M^J'END Validation Testing.' );
- END; { fultest }
- { start of timing }
- PROCEDURE timetest( loops: INTEGER );
- { organize the time testing of various routines }
- VAR
- a, b: timearty;
- i, x: INTEGER;
- by: BYTE;
- empty: REAL; { time for empty loops }
- calltime: REAL; { time for loops and empty procedure }
- PROCEDURE crcmt( VAR dx: INTEGER; data: INTEGER);
- BEGIN
- END;
- PROCEDURE showtimedif( a, b: timearty; c: INTEGER );
- { display a line of time results }
- VAR
- dif, Noloop, NoloopNocall: REAL;
- BEGIN
- dif := timedif( a, b );
- Noloop := dif - empty;
- NoloopNocall := dif - calltime;
- WRITE(
- Noloop:7:3, ' ', NoloopNocall:7:3,' ',
- Noloop * (1000.0 / c):7:3, ' ', NoloopNocall * (1000.0 / c):7:3 );
- END; {showtimedif}
- BEGIN {timetest}
- calltime := 0.0; {the global}
- by := $a5; {your typical data byte}
- WRITELN(
- ^M^J^J'Turbo Pascal runs CRC-CCITT on 8088 under Bare MSDOS',
- ^M^J' FOR ', loops,' OPERATIONS; 7.16 MHz CLOCK (multiply by 1.5 for 4.77 MHz)' );
- WRITE( ^M^J'Empty loop: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- ;
- readhms( b );
- empty := timedif( a, b); {the global}
- WRITE( empty:5:3, ' secs' );
- WRITE( ^M^J'Empty procedure in loop: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- crcmt( x, by );
- readhms( b );
- calltime := timedif( a, b ); {another global}
- WRITE( calltime:5:3, ' secs' );
- WRITE( ^M^J' (procedure overhead alone = ',
- (calltime - empty) * (1000.0 / loops):6:3,
- ' msec each)' );
- WRITELN(
- ^M^J^J' ', loops:5, ' Uses (secs) 1 Use (msec)',
- ^M^J' Procedure In Line Procedure In Line' );
- WRITE(
- ^M^J'Pascal Bit-by-Bit: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- crcittby( x, by );
- readhms( b );
- showtimedif( a, b, loops );
- WRITE(
- ^M^J'Pascal Fast B-B-B: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- crcfbbb( x, by );
- readhms( b );
- showtimedif( a, b, loops );
- WRITE(
- ^M^J'Pascal Byte: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- crcitta( x, by );
- readhms( b );
- showtimedif( a, b, loops );
- WRITE(
- ^M^J'Pascal Table: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- crctablu( x, by );
- readhms( b );
- showtimedif( a, b, loops );
- WRITE(
- ^M^J'Machine Code Byte: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- mcrcitt1( x, by );
- readhms( b );
- showtimedif( a, b, loops );
- WRITE(
- ^M^J'Machine Code Table: ' );
- readhms( a );
- FOR i := 1 TO loops DO
- mcrcitt3( x, by );
- readhms( b );
- showtimedif( a, b, loops );
- WRITELN;
- END; {timetest}
- PROCEDURE datatimes;
- { data character times, for comparison }
- CONST
- rates: ARRAY[1..7] of INTEGER =
- ( 12, 24, 48, 96, 192, 384, 576 );
- VAR i: INTEGER;
- BEGIN
- WRITELN( ^M^J^J'Character Times for Various Bit Rates: ' );
- WRITE( ^M^J' bits/sec char/sec msec/char');
- FOR i := 1 TO 7 DO
- WRITE( ^M^J, '':4, (100.0 * rates[i]):5:0, '':8,
- (10.0 * rates[i]):5:0, '':8,
- (100.0 / rates[i]):5:3 );
- WRITELN;
- END; {datatimes}
- BEGIN { main: crctime }
- WRITELN;
- ConOutPtr := OFS( bdosch ); {output through MSDOS}
- ownership;
- fultest( 100 );
- timetest( 10000 );
- datatimes;
- END.
- { end file crctime.pas }