                        THE CRC
    A POWERFUL ERROR-CHECKING TECHNIQUE YOU CAN USE
    By Roxton Baker, Box 8272, APO San Francisco 96555


The error-checking that is done during program transfers on the TRS-80 is of
varying quality, ranging from none at all to very good.  The worst case is a
CSAVE under Basic where not even a single checksum follows the program data
out to tape.  This means that later, when that program is read back in, there
is no way of guaranteeing that it is good.  This unbelievable omission has
cost thousands of user hours.

Much better than this is the format of a SYSTEM tape.  Here the data is
written out in blocks; each block is followed by a one-byte checksum of that
block.  This checksum is generated by adding together, without carries, all of
the bytes of data (256 plus some overhead) in that block.  When the program is
later read back in each incoming block of data is checksummed in the same
fashion, and that checksum is compared to the one stored on the tape.  If the
two checksums are different there has certainly been an error in the saving
and loading of the program.  If the two checksums are the same there has
probably not been an error.  Multiple errors that happen to cause the
checksums to come out the same will go undetected.

Better still is the way data is stored on disk.  As with a SYSTEM tape, data
is transferred and stored in blocks of 256 bytes, which on a disk comprise one
sector.  Each sector of data is followed not by a single checksum byte but
rather by two CRC bytes.  These two bytes provide the error-checking.

CRC stands for Cyclic Redundancy Code.  It represents a process of taking a
block of data bytes and performing what may be thought of as a very fancy and
involved checksum on them.  A CRC check can be used in any data transmission,
whether it be to disk (or tape) and back again, or over telephone lines.  Just
as with a checksum the two CRC bytes are stored (or transmitted) along with
the block of data.  Upon retrieval (or reception) they are compared with two
CRC bytes newly calculated from the data.  A bad comparison means there was
certainly an error in transmission.  A good comparison means that there was
almost certainly no error in transmission.

Although CRC checks are often used for error correction, in our disk system
they are merely relied upon for error detection.  For this they are very good.
As a simple example, consider the transmission of the two hex bytes of data 7F
A2.  If a one-byte checksum were used it would be 21, the sum of these bytes
without carry.  Obviously, there are many pairs of data bytes that would give
this same checksum.  Even if a two-byte checksum were used, in this case 01
21, there are still almost two hundred pairs of data bytes that would checksum
the same.  However, if these two data bytes were followed by two CRC bytes, in
this case 90 C0, it would be impossible to overlook an error in transmission.
This is because no two data bytes other than 7F A2 will generate the two CRC
bytes 90 C0.

A two-byte example proves nothing in general, but it is a fact that for any
block of data a CRC will provide a much more unique "signature" than will a
simple checksum.  This means that multiple errors are much more likely to be
detected.  Going along with this increase in error detecting capability is an
increase in difficulty in generating the check bytes.  It is no simple matter
to CRC even one byte of data - if nothing else, it takes time.

In the TRS-80, CRC checks are used primarily in the transfer of disk data.
All data transfers to and from the disk are handled by an integrated circuit
floppy disk controller, or FDC.  The particular FDC used is a Western Digital
FD1771; the details of its addressing by the Z80 CPU are covered in Bill
Barden's excellent TRS-80 Disk Interfacing Guide, which may still be available
from The Alternate Source or from Bill himself.  When reading or writing a
sector of data this FDC will automatically generate, in hardware, the two CRC
bytes for that data.  Only in hardware could the CRC bytes be generated fast
enough to accommodate the speed of disk data transfer.  In fact, even a simple
one-byte checksum would probably have to be done in hardware, so using a CRC
costs nothing extra.  Disk owners are fortunate in this; left to themselves,
the TRS-80 designers might have given us a DSAVE.

There are many different ways of generating CRC bytes from data.  Each way
signatures the data differently and results in different CRC bytes.  The 1771
FDC uses the IBM SDLC standard.  That means that there are always two CRC
bytes and that they always start off, before any data is handled, with an
initial value of FF FF hex.  The standard also defines the exact algorithm
that will be used in calculating the new value of the CRC bytes from their
current values and the value of the incoming data byte.  The shorthand way of
describing such a CRC algorithm is with a "polynomial", which defines a
sequence of shifting and Exclusive-Or'ing of the data bits and the CRC bits.
For your reference, the IBM SDLC polynomial is:

                 X^16 + X^12 + X^5 + 1

Note that up-arrows may have printed as brackets.

Don't try to make any sense of this polynomial as it stands; the mathematical
underpinnings for it, and for the use of CRC's in general, are closely allied
with magic.  The best reference I have found yet is Ref. 1, which discusses
CRC's from a straightforward hardware point of view.

Fortunately, it is not necessary to understand CRC's in order to use them.
What's really needed, should you wish to decipher the disk CRC's or perhaps to
use CRC's in your own tape routine or data transmission scheme, is a reliable
method of producing them.  Hand-calculating a CRC from just one byte of data
is tedious and error-prone, and too slow even for TRS-80 tape.  In fact, if
CRC's are to be computed at any speed, the efficiency of the method used will
be important.

Listed below are two programs that will aid in the generation of CRC bytes.
Fig. 1 is a Basic program suitable for hand-entry of data bytes in hex.  Each
new pair of CRC bytes generated is displayed.  This program directly
implements the cross-table shown by Mr. Vasa in Ref. 2, since speed is not
critical here.  Note that "<>" is used for Exclusive-Or; the technique of
using a "-" (as shown in 80-US Journal) is incorrect and fails for three or
more operands.  This program was written as an exercise, and should not be
taken as a model of programming.  It is convenient when the CRC of only a few
bytes of data is to be generated.  A useful improvement to this program would
be to allow for the entry of ASCII data also.

The Basic program could of course be modified to CRC blocks of data, but at
some point it will be necessary to use assembly language.  Certainly this will
be required if these CRC bytes are being used in a system.  I was pleased to
find, also in Ref. 2, an excellent machine-language routine that does a fast
parallel generation of CRC bytes according to the IBM SDLC standard.  It was
originally written for the F8 microprocessor; Ref. 3 gave it modified for the
6800, from which I made a direct translation into Z80 code.  This last routine
is shown as subroutine NEWCRC in the assembler listing of Fig. 2.  The calling
portion of Fig. 2 is just a simple loop which calls NEWCRC as required to
generate the new CRC bytes for each byte of stored or incoming data.  The
actual calculation of the CRC bytes in NEWCRC takes about 93 microseconds for
each byte of data.

Compared to a simple checksum this is very slow, but if the time is available
the use of a CRC should be considered.  The data received or retrieved will
almost certainly be OK if the CRC bytes check out.  And the software overhead,
as shown below, is not too large to incorporate if you are setting up a system
from scratch.

In regards to this, it appears that the DOS already contains a routine to CRC
a block of data.  This is the routine that is used to check DOS passwords.
Whenever a disk file is accessed, the 8-character password given by the user
is stored at 5155-515C hex.  A routine at 50D1-50FC takes these bytes in
reverse order and manipulates the bits of each one, resulting finally in a
two-byte signature which is returned in HL.  The method used by this routine
is not exactly the SDLC standard, but it does appear to be a CRC algorithm.
Therefore, it could be used to error-check a block of data.  To use it in this
way, set DE to the address of the last byte in the block and set B to the
number of bytes in the block.  Set HL to some fixed value, say FFFF.  Call
50DD as a subroutine.  On return, the two CRC bytes will be in HL.

The disadvantages to using this resident DOS routine are that it is set up to
handle blocks of data rather than single bytes, and that it is slow.  Compared
to the program of Fig. 2, the DOS routine will take about twice as long to CRC
a block of code.  Also, it will be difficult to use this routine for blocks of
more than 256 bytes because it uses only the B register as a counter.  Still,
there are no doubt applications that can use this "free code" advantageously.


References:

1.  K. Rallapalli, "CRC Error-Detection Schemes Ensure Data Accuracy", EDN,
September 5 1978.  2.  S. Vasa, "Calculating an Error Checking Character in
Software", Computer Design, May 1976, pp 190-192.  3.  H. Socha, Letter,
Computer Design, May 1979, pg 6.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

50 REM            **   CRC GENERATOR   **
60 REM
70 REM  THIS PROGRAM WILL SIMULATE THE CRC GENERATING ALGORITHM
80 REM  USED BY THE TRS-80 FLOPPY DISK CONTROLLER.
90 REM   THERE ARE TWO CRC BYTES, WHICH ARE ALWAYS INIT-
100 REM  IALIZED TO FFFF (HEX).  THIS VALUE CHANGES AS EACH DATA
110 REM  BYTE IS ACCOUNTED FOR.  IN THIS PROGRAM, THE TWO CRC
120 REM  BYTES ARE KEPT IN C(15) MSB THROUGH C(0) LSB.  THE DATA
130 REM  BYTE INPUT IS KEPT IN D(7)-D(0).  ANY NUMBER OF DATA
140 REM  BYTES CAN BE ENTERED IN SEQUENCE, AT THE PROMPT.
150 REM
160 REM  ROXTON BAKER, BOX 8272, APO SAN FRANCISCO 96555
170 REM
180 CLS: PRINT@150,"CRC GENERATOR" :PRINT :PRINT
190 DEFINTI,J,K,L,C,A,D
200 DIM A(8),C(16),D(8)
210 C1=255 : AI=C1 : GOSUB 890
220 FOR K=0 TO 7
230 C(K+8)=A(K)
240 NEXT K
250 C2=255 : AI=C2 : GOSUB 890
260 FOR K=0 TO 7
270 C(K)=A(K)
280 NEXT K
290 MS=0 : AI=0 : INPUT"ENTER DATA BYTE IN HEX  ";H$
300 REM  CONVERT HEX BYTE INTO DECIMAL DIGIT
310 FOR K=1 TO 0 STEP -1
320 L=ASC(MID$(H$,2-K,1))
330 IF (L>=65) AND (L<=70) THEN M=L-55 : GOTO 370
340 IF (L>=48) AND (L<=57) THEN M=L-48 : GOTO 370
350 PRINT"INVALID HEX BYTE  --  TRY AGAIN"
360 MS=-1 : K=0 : GOTO 380
370 AI=AI+INT(16^K+.25)*M   'Note up-arrow may print as bracket
380 NEXT K
390 IF MS THEN 290
400 GOSUB 890
410 FORK=0 TO 7
420 D(K)=A(K)
430 NEXT K
440 GOSUB 630
450 REM  NOW CONVERT NEW CRC BYTES TO HEX FOR DISPLAY
460 T=19
470 FOR K=0 TO 3
480 T=T-4 : CT=0
490 CT=CT-8*C(T)
500 CT=CT-4*C(T-1)
510 CT=CT-2*C(T-2)
520 CT=CT-C(T-3)
530 IF CT>=10 THEN NC$(K)=CHR$(CT+55) ELSE NC$(K)=CHR$(CT+48)
540 NEXT K
550 PRINT"NEW CRC BYTES ARE :  ";
560 FOR K=0 TO 3
570 PRINT NC$(K);
580 IF K=1 PRINT" ";
590 NEXT K
600 PRINT : PRINT
610 GOTO 290
620 REM  THIS SUBROUTINE PERFORMS THE CRC ALGORITHM
630 PI=C(15)<>D(7)
640 PJ=C(14)<>D(6)
650 PK=C(13)<>D(5)
660 PL=C(12)<>D(4)
670 PM=C(11)<>D(3)<>PI
680 PN=C(10)<>D(2)<>PJ
690 PO=C(9)<>D(1)<>PK
700 PP=C(8)<>D(0)<>PL
710 C(15)=C(7)<>PM
720 C(14)=C(6)<>PN
730 C(13)=C(5)<>PO
740 C(12)=C(4)<>PI<>PP
750 C(11)=C(3)<>PJ
760 C(10)=C(2)<>PK
770 C(9)=C(1)<>PL
780 C(8)=C(0)<>PM
790 C(7)=PI<>PN
800 C(6)=PJ<>PO
810 C(5)=PK<>PP
820 C(4)=PL
830 C(3)=PM
840 C(2)=PN
850 C(1)=PO
860 C(0)=PP
870 RETURN
890 REM   THIS SUBROUTINE TAKES AN INTEGER AI FROM 0-255 AND
900 REM   CONVERTS IT INTO -1'S AND 0'S IN PREPARATION FOR THE
910 REM   USE OF ITS BITS IN LOGICAL OPERATIONS.  THESE BITS 
920 REM   ARE RETURNED AS A(7) MSB - A(0) LSB.
930 A(7)=-SGN(128 AND AI)
940 A(6)=-SGN(64 AND AI)
950 A(5)=-SGN(32 AND AI)
960 A(4)=-SGN(16 AND AI)
970 A(3)=-SGN(8 AND AI)
980 A(2)=-SGN(4 AND AI)
990 A(1)=-SGN(2 AND AI)
1000 A(0)=-SGN(1 AND AI)
1010 RETURN


         Figure 1  BASIC program for CRC calculation


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00010 ; THIS ROUTINE WILL CALCULATE THE SDLC CRC (AS USED IN
00020 ; THE TRS-80 FLOPPY DISK) FOR ANY BLOCK OF DATA IN
00030 ; MEMORY BETWEEN 1 AND 65K BYTES LONG.  THE ADDRESS AT
00040 ; WHICH TO START IS PASSED TO THIS ROUTINE IN HL.  THE
00050 ; NUMBER OF BYTES TO CRC CHECK MUST BE STORED IN NBYTES.
00060 ; THE INITIAL VALUE OF THE CRC MUST BE STORED IN CRCINT.
00070 ; IT SHOULD NORMALLY BE FF FF.  THE NEW CRC
00080 ; VALUE IS KEPT IN DE, AND IS RETURNED TO THE CALLING
00090 ; PROGRAM (ASSUMED TO BE BASIC), IN HL.
00100 ;
00110 ; BY ROXTON BAKER, BOX 8272, APO SAN FRANCISCO 96555
00120 ;
00130 NBYTES      EQU       07FF4H       ;# BYTES TO CRC HERE
00140                                    ;  IN 7FF4, 7FF5.
00150 CRCINT      EQU       07FF6H       ;NORMALLY FF FF HERE.
00160 GETARG      EQU       0A7FH        ;GET USR ARG IN HL
00170             ORG       07D50H       ;PUT IT ANYWHERE.
00180             CALL      GETARG       ;GET START ADDRESS IN HL
00190             LD        BC,(NBYTES)  ;1 GIVES 1 BYTE, 0 GIVES
00200                                    ;  65K BYTES
00210             LD        DE,(CRCINT)  ;STARTING VALUE OF CRC
00220 CRC1        PUSH      BC           ;SAVE COUNTER
00230             CALL      NEWCRC       ;COMPUTE NEW CRC BYTES.
00240             POP       BC           ;RESTORE COUNTER.
00250             INC       HL           ;POINT TO NEXT DATA BYTE
00260             DEC       BC           ;CHECK IF ALL DONE.
00270             LD        A,B
00280             OR        C
00290             JR        NZ,CRC1      ;IF NOT, DO ANOTHER.
00300             EX        DE,HL        ;PUT NEW CRC IN HL
00310             JP        0A9AH        ;  FOR RETURN TO BASIC.
00320 ;
00330 ;  THIS SUBROUTINE WILL FACTOR ONE BYTE INTO THE IBM
00340 ; SDLC CRC CALCULATION, GIVEN THE STARTING CRC IN DE AND
00350 ; THE ADDRESS OF THE BYTE TO BE ACCOUNTED FOR POINTED TO
00360 ; BY HL.  THE NEW CRC IS RETURNED IN DE.  THIS ROUTINE
00370 ; IS THE Z80 VERSION OF ONE DUE TO VASA, COMPUTER DESIGN
00380 ; MAY 1976, PG. 190, AS MODIFIED BY SOCHA, COMPUTER
00390 ; DESIGN MAY 1979, PG. 6.
00400 ;
00410 NEWCRC      LD        A,(HL)       ;GET NEXT DATA BYTE
00420             XOR       D
00430             LD        D,A
00440             SRL       A
00450             SRL       A
00460             SRL       A
00470             SRL       A
00480             XOR       D            ;GENERATE IJKLMNOP
00490             LD        D,E          ;SWAP TWO CRC BYTES
00500             LD        E,A          ;  PER SOCHA
00510             RL        A
00520             RL        A
00530             RL        A
00540             RL        A
00550             LD        C,A          ;SAVE MNOPXIJK
00560             RL        A
00570             RL        A
00580             AND       1FH          ;SELECT 000IJKLM
00590             XOR       D
00600             LD        D,A
00610             LD        A,C
00620             AND       0F0H         ;SELECT MNOP0000
00630             XOR       D
00640             LD        D,A          ;CRCH DONE IN D
00650             LD        A,C
00660             RL        A
00670             AND       0E0H         ;SELECT NOP00000
00680             XOR       E
00690             LD        E,A          ;CRCL DONE IN E
00700             RET
00710;
00720             END       402DH        ;TO DOS AFTER LOADING.


  Figure 2. Assembler program to CRC check a block of data

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 