/* * crckk.c -- CP/M Universal CRC utility for CP/M * * Usage: * crckk [-t|b|c|u] [-a|-s [-p]] [filename ... ] * * Calculates a 16-bit cyclic redundancy check on its input files and * prints the resulting number in hexadecimal. CRCK(K) is manually invoked * on two versions of the same file to ensure that they are the same. * Prints the the filename, size in bytes or sectors depending on the * option flag, and the CRC. If a file has been patched using the '-p' * option, then the file can be "independantly" tested by looking for a * zero CRC result. * * Options: * -t Perform CRCK on a CP/M text file that is stored as a CP/M * file. CTL-Z is used as valid EOF. * * -b Perform binary CRCK on a regular CP/M file. Takes whatever * is there. * * -c Perform CRCK on a CP/M ".COM" file. Handled the same as * the -b flag except sectors are reported rather than bytes. * * -u Perform CRCK on a CP/M file as if it were a UNIX text file. * CR's are ignored, and CTL-Z is a valid EOF. * * * * -a Performs the above crc calculations, but uses a CRC * calculation compatible with "ARC". * * -l Performs the above crc calculations, but uses a CRC * calculation compatible with "LU" libraries. * * -s Performs the above crc calculations, but uses a CRC * calculation compatible with "CCITCRC". * * * * -p Patches the named file's last two bytes to make the * file CRC equal zero USING THE SAME CRC. This option * is only available with the -a or -s option. Option not * available with '-t' or '-u' where the end of file * isn't looked at anyway. * * * Beware that some files may not be patchable. If the file * is a text file, then you are safe. If it is a binary * file that either "ends" before the last two bytes, OR doesn't * have a CTL-Z in it's last physical sector, then you're also safe. * The only "problem" file would be the case of a binary file that * uses it's last two bytes in it's last-physical-sector AND its * got CTL-Z's as part of the code in that last sector. * * CRCKK will NOT patch the last sector when '-p' is used if that * last sector would end up w/o a CTL-Z in it. In those cases, * another CTL-Z'd sector is added on to the file. * * If no option flag is chosen, the default option is -b. * * Wildcards may, of course, be used and the program may be used in * pipelines. * * *---------------------------------------------------------------------------- * Version 2.0 mods by Ben Goldfarb (decvax!ucf-cs!goldfarb or * Goldfarb.ucf-cs @ Rand-Relay) * * Added CP/M text and binary file modes and changed to * use standard stream I/O. * * * Version 3.0 Modified it for running under CP/M. Included * in the changes are the redefiniton of "-t" modifier as * to make sense on the CP/M "end" of things. * This is good for downloading text files (like shar files) * from UNIX. If you download a text file "as is" (pre-cp/m'd * but not FROM a cp/m system) from UNIX OR, your modem * program doesn't "fill with multiple CTL-Z's", then "-t" will * match Unix's crck. Either way this *new* function is needed. * * Renamed it crckk whereas this version is not readily * portable backwards. * * I changed crck calculating routines into in-line assembly * language (the CTL-Z EOF looker as well). * * I also changed the I/O (actually the "I") to unbuffered * (one component that makes it much faster). * * All in all, this version actually runs FASTER (by quite a * bit on my test file) than the CP/M assembly language * version crck44(.asm)! (At least on my system). * * Note that the compiled version sorts wildcards, error * messages can be redirected out stderr ( >> errfile ), etc * "just like UNIX". :-) More or less. * * * Mike Kersenbrock * tektronix!copper!michaelk * Aloha, Oregon 11/86 * * * Version 3.1 Cleaned up initial "mode-selected" messages to better * reflect the mode being run. * * Deleted ITS "-i" option mode. * * Renamed "-u" mode (binary mode) to "-b". * * Added "-u" mode that calculates CRCK of a text file * as if that file were a UNIX (tm of AT&T) file, or any * other system that uses LF rather than CRLF as newline. * * * * Mike Kersenbrock * tektronix!copper!michaelk * Aloha, Oregon 12/86 * * * Version 3.2 Added "-a" option and fixed sector-count bug. * (This version not distributed) * * * Mike Kersenbrock * tektronix!copper!michaelk * Aloha, Oregon 4/1987 * * Version 3.3 Added "-s","-l", and "-p" options. I probably should rename * this thing to "UNIVCRC" or the like. Getting pretty * universal. Maybe next time. * * * Mike Kersenbrock * tektronix!copper!michaelk * Aloha, Oregon 4/1987 */ #include "c:stdio.h" /* Keep my compiler stuff in RAMDISK "C:" */ #include "c:fcntl.h" #define isatty istty /* I misnamed it when I wrote it for my library */ /* Someday I'll fix it. -mdk */ #define VERSION 33 /* Version 3.3 */ #define SECSIZ 128 /* CP/M sector size for fill */ #define CTLZ 'Z' - 0x40 /* Fill character for text files */ /* * Z80 psuedo-mnemonics for the assembly language sections */ #define DJNZ db 10h /* DJNZ's opcode-only */ #define EXAF db 08h /* EX af,af' */ #define EXX db 0d9h /* EXX */ #define LDED db 0edh,5bh /* LD DE,(nn) */ #define CPIR db 0edh,0b1h /* Z80 Block-compare */ #define SBCBC db 0edh,042h /* SBC HL,BC */ char cflag = 0; /* CP/M binary file w/sectors */ char tflag = 0; /* CP/M text file */ char bflag = 0; /* Binary CP/M file */ char uflag = 0; /* quasi-Unix-text file */ char aflag = 0; /* ARC-compatible CRC calculation */ char lflag = 0; /* LU-compatible CRC calculation */ char sflag = 0; /* CCITCRC-compatible CRC calculation */ char pflag = 0; /* Patch the file for zero CRC */ char *Tbuf; /* pointer to large file buffer */ unsigned int Tbufsize; /* size of the above buffer */ unsigned short crckcalc(); /* CRC calculation function */ unsigned short arccalc(); /* CRC calculation function */ unsigned short arcnocr(); /* CRC calculation function */ unsigned short gpcalc(); /* CRC calculation function */ unsigned short gpnocr(); /* CRC calculation function */ unsigned int lutable(); /* don't ask */ unsigned int cctable(); /* * This is a table pointer for those cases where the algorithm is * the same, but only the table and/or CRC initializer is different. */ char *Table; unsigned int Crcount; /* Count of CR's ignored in the "-u" mode */ char *Currentfile; /* Name of the file currently being worked on*/ main(argc, argv) int argc; char **argv; { int err = 0; ++argv; while ((argv)[0][0] == '-') { switch (tolower(argv[0][1])) { case 'a': ++aflag; break; case 't': ++tflag; break; case 'c': ++cflag; break; case 'b': ++bflag; break; case 'u': ++uflag; break; case 's': ++sflag; break; case 'l': ++lflag; break; case 'p': ++pflag; break; default: printmode(stderr); goto usage; } --argc; ++argv; } if (!tflag && !cflag && !uflag) { ++bflag; } if (aflag + sflag + lflag > 1) { perror( "flags '-a','-l',and '-s' are not allowed at same time\n"); goto usage; } if (pflag & !(aflag || sflag || lflag)) { perror("'-p' flag requires either '-a','-l',or '-s' flag\n"); goto usage; } if (pflag & (tflag || uflag)) { perror("'-p' patching doesn't work with '-t' or '-u'\n"); goto usage; } if ((tflag + cflag + uflag + bflag) > 1 ) { perror("multiple flags [t,b,c and u] not allowed\n"); goto usage; } /* * Initialize table pointer for those cases where it will * be used. */ if (sflag) { Table = cctable; } else if (lflag) { Table = lutable; } /* * Make sure one copy of the "mode" selected's make it to * each redirected file and to the screen (if possible). */ printmode(stdout); if (!(isatty(2) && isatty(1))) { printmode(stderr); } /* * Find a suitable large data buffer area, we want this to HUMMMMMM */ for (Tbufsize = 0x7ffd ; ((Tbuf=malloc(Tbufsize)) == NULL) ; Tbufsize /= 2); if (argc == 1 ) { /* we're just taking stdin from somewhere */ if (pflag) { perror("Can't '-p' patch stdin\n"); exit(POSTERROR); } docrck("stdin"); exit(0); } else { /* we're doing a named file or a list of same */ for (; --argc; ++argv) { err = 0; /* * 1. Changed to unbuffered, it's much faster * * 2. At least in this Aztec C II compiler, closing channel 0 followed * by opening a channel, will always result in channel 0 being * used in the open call. Essentially an unbuffered freopen. * * -Mike Kersenbrock */ close(0); if (open(*argv,O_RDONLY) != 0) { perror(*argv); ++err; } Currentfile = *argv; if (!err) docrck(*argv); } exit(0); } usage: fprintf(stderr, "Usage: crckk [-t|b|c|u] [-a|l|s [-p]] [filename ... ]\n\n"); fprintf(stderr, "\t-t CRCK on CP/M text file honoring CTL-Z EOF.\n"); fprintf(stderr, "\t-b .... on a CP/M file. Takes whatever is there (binary).\n"); fprintf(stderr, "\t-c .... on a CP/M \".COM\" file. Same as -b, but w/sector count.\n"); fprintf(stderr, "\t-u .... on CP/M text file but simulating a UNIX file crck.\n"); fprintf(stderr, "\n\t-a Do the above with ARC compatible polynomial\n"); fprintf(stderr, "\t-l Do the above with LU & XMODEM compatible polynomial\n"); fprintf(stderr, "\t-s Do the above with CCITCRC compatible polynomial\n"); fprintf(stderr, "\n\t-p Patch the files(s) to make them have a zero CRC\n"); exit(POSTERROR); } docrck(name) /* Calculate and print a "CRCK" for stdin stream. */ char *name; { long nsec; static unsigned short oldcrck; static unsigned short addercrc; register int realcount; register int count; register int eoff; static char adderflag; char lastsector[128]; int patchfile; /* * Set initial condition for the CRC being used. */ if (sflag) { oldcrck = 0xffff; } else { oldcrck = 0; } count = 0; eoff = 0; nsec = 0L; adderflag = 0; chekkbd(); /* punt w/ CTL-C under CP/M */ if (tflag || uflag) { while ((count=read(0,Tbuf,Tbufsize)) > 0 && eoff==0){ chekkbd(); /* punt w/ CTL-C under CP/M */ if ((realcount=look4eof(Tbuf,count)) != count) eoff = 1; if (tflag) { if (aflag) { oldcrck=arccalc(realcount,Tbuf,oldcrck); } else if (sflag || lflag) { oldcrck=gpcalc(realcount,Tbuf,oldcrck); } else { oldcrck=crckcalc(realcount,Tbuf,oldcrck); } } else { Crcount = 0 ; if (aflag) { oldcrck=arcnocr(realcount,Tbuf,oldcrck); } else if (sflag || lflag) { oldcrck=gpnocr(realcount,Tbuf,oldcrck); } else { oldcrck=crcknocr(realcount,Tbuf,oldcrck); } } nsec += ((long)((long)realcount-(long)Crcount)); } } else { /* bflag or cflag -- do a quick crck */ while ((count = read(0,Tbuf,Tbufsize)) > 0) { chekkbd(); /* punt w/ CTL-C under CP/M */ /* * If it didn't fetch Tbufsize nr of bytes, then it * had to have "hit" the end of file... */ if (pflag && (count != Tbufsize) && count > 2) { if ((aflag || sflag || lflag ) && !tflag && !uflag) { adderflag = 1; count -= 2; } } if (aflag) { oldcrck = arccalc(count,Tbuf,oldcrck); } else if (sflag || lflag) { oldcrck = gpcalc(count,Tbuf,oldcrck); } else { oldcrck = crckcalc(count,Tbuf,oldcrck); } if (adderflag) { addercrc = oldcrck; if (aflag) { oldcrck = arccalc(2,Tbuf+count,oldcrck); } else if (sflag || lflag) { oldcrck = gpcalc(2,Tbuf+count,oldcrck); } else { oldcrck = crckcalc(2,Tbuf+count,oldcrck); } count += 2; } if (!cflag) nsec += (long)count; /* here nsec is for BYTES */ else nsec += ((long)((long)count + (long)SECSIZ - 1L)/ (long)SECSIZ ); } } if (pflag) putchar('\n'); printf("%-18s", name); printf(" (%7ld %-7s) ==> %04x\n", nsec, (bflag||tflag||uflag) ? "bytes" : "sectors", oldcrck); if (pflag && !adderflag) { perror("Can't patch for internal reasons."); } else if (pflag) { if ((patchfile=open(Currentfile,O_RDWR)) < 0) { fprintf(stderr, "\nERROR: Couldn't open %s for patching\n",Currentfile); } else { fprintf(stderr,"Patching %s ....\n",Currentfile); lseek(patchfile,-128L,2); read(patchfile,lastsector,128); if (oldcrck == 0) { fprintf(stderr, "ERROR: File %s is already patched\n\n", Currentfile); } else if (aflag) { lastsector[126] = (char) (addercrc & 0xff) ; lastsector[127] = (char) (addercrc>>8); } else { lastsector[126] = (char) (addercrc>>8); lastsector[127] = (char) (addercrc & 0xff) ; } if (oldcrck != 0) { for (eoff = 0 ; eoff < 126 ; eoff++) { if (lastsector[eoff] == 0x1a) break; } if (eoff == 126) { fprintf(stderr, "NOTE: Added a sector to file %s (else would result w/o CTL-Z).\n\n", Currentfile); for (eoff = 0 ; eoff < 126 ; eoff++) { lastsector[eoff] = 0x1a; } if (aflag) { oldcrck = arccalc(126,lastsector,oldcrck); } else if (sflag || lflag) { oldcrck = gpcalc(126,lastsector,oldcrck); } else { oldcrck = crckcalc(126,lastsector,oldcrck); } if (aflag) { lastsector[126] = (char)(oldcrck & 0xff); lastsector[127] = (char)(oldcrck>>8); } else { lastsector[126] = (char)(oldcrck>>8); lastsector[127] = (char)(oldcrck & 0xff); } lseek(patchfile,0L,2); write(patchfile,lastsector,128); } else { lseek(patchfile,-128L,2); write(patchfile,lastsector,128); } close(patchfile); } } } } perror(string) char *string; { fprintf(stderr,"\nERROR: %s\n",string); } /* * Calculate crck on a buffer. Uses algorithm of CRCK.COM prior to V5.0 . * Buffsize is really "valid-data-size", and must be >= 1. * * returns: "new" crck calculation -Mike Kersenbrock * tektronix!copper!michaelk * * crckcalc(buffsize,buffer,oldcrc) * unsigned int buffsize; <==== "equivalent to that" * char *buffer; * unsigned int oldsum; */ #asm crckcalc_: call popargs ; ; registers: CB == Count (yes, backwards) ; DE == Pointer ; HL == OldCrc ; mov a,b ; Get count LSB ora a ; is it a zero? jnz crcloop ; nope dcr c ; yes, correct initial-condition anomaly where ; zero == 256 in DJNZ parlance..... crcloop: dad h ; (crck << 1) w/msb into carry EXAF ; save flags for a sec ldax d ; get data byte inx d ; update pointer for next time add l ; add low half, note high half doesnt change mov l,a ; EXAF ; get shift-flags back jnc noone ; mvi a,097h ; if (original crck & 0x8000) xra l ;--- mov l,a ; |- hl = (orig crck <<1) ^ 0xA097 mvi a,0a0h ; | xra h ; | mov h,a ;--- noone: DJNZ ; db (crcloop-noone)-2 ; loop for the LSB of the count (IN *B* ) mov a,c ; get msb dcr c ; pre-decrement-extend just in case ora a ; is count msb a zero also? jnz crcloop ; nope, go do another 256 loops alldone: pop b ; return value of the register variable mov a,h ; set zero flag... ora l ; ... to HLs value ret ; return w/new crckk as value (in HL) #endasm /* * Calculate crck on a buffer. Uses algorithm of CRCK.COM prior to V5.0 . * Buffsize is really "valid-data-size", and must be >= 1. * * This routine ignores CR's in the data, and increments CR count in * global variable "Crcount" by the number of CR's found. * * This is done separate from the above routine to keep this program, * particularly the above routine, relatively fast. * * returns: "new" crck calculation -Mike Kersenbrock * tektronix!copper!michaelk * * crcknocr(buffsize,buffer,oldcrc) * unsigned int buffsize; <==== "equivalent to that" * char *buffer; * unsigned int oldsum; */ #asm crcknocr_: call popargs ; ; registers: CB == Count (yes, backwards) ; DE == Pointer ; HL == OldCrc ; mov a,b ; Get count LSB ora a ; is it a zero? jnz crckloop ; nope dcr c ; yes, correct initial-condition anomaly where ; zero == 256 in DJNZ parlance..... crckloop: ldax d ; get data byte cpi 0dh ; CR? jnz doloop ; nope, continue on inx d ; yep, so update pointer EXX ; swap whole register set BC,DE,HL lhld Crcount_ ; get CR counter inx h ; count the CR shld Crcount_ ; restore CR counter EXX ; get "regular" registers back jmp none ; and continue on with loop doloop: dad h ; (crck << 1) w/msb into carry EXAF ; save flags for a sec ldax d ; get data byte inx d ; update pointer for next time add l ; add low half, note high half doesnt change mov l,a ; EXAF ; get shift-flags back jnc none ; mvi a,097h ; if (original crck & 0x8000) xra l ;--- mov l,a ; |- hl = (orig crck <<1) ^ 0xA097 mvi a,0a0h ; | xra h ; | mov h,a ;--- none: DJNZ ; db (crckloop-none)-2 ; loop for the LSB of the count (IN *B* ) mov a,c ; get msb dcr c ; pre-decrement-extend just in case ora a ; is count msb a zero also? jnz crckloop ; nope, go do another 256 loops jmp alldone #endasm /* * Search a buffer of length maxcount, and return the number * of characters *before* finding CP/M's EOF. If EOF is not found * then maxcount is returned. Uses Z80 Block-search instruction. * * This is for a Z80 only. -Mike Kersenbrock * tektronix!copper!michaelk * look4eof(buffer,maxcount) * char *buffer; * int maxcount; * */ #asm look4eof_: lxi h,2 dad sp mov e,m inx h mov d,m ; buffer pointer is now in DE push b ; Save incoming register variable inx h mov c,m inx h mov b,m ; maxcount is now in BC xchg ; buffer pointer is now in HL mov e,c mov d,b ; (save original count in DE) mvi a,1ah ; EOF in accumulator CPIR ; Z80 Block-compare look for EOF xchg ; put original count into HL jnz nofound ; nope, hadnt found EOF ; else,... stc ; set carry flag SBCBC ; subtract current count(BC) from orig count-1 ; (leave new actual count in HL (rtn value)) nofound: ; The calling count is still in HL mov a,h ora l ; set zero flag to HLs contents pop b ; return register variable back again ret #endasm /* * Calculate crck on a buffer. Uses the same polynomial as the popular * "ARC" archive program. * * Buffsize is really "valid-data-size", and must be >= 1. * * returns: "new" crck calculation -Mike Kersenbrock * tektronix!copper!michaelk * * arccalc(buffsize,buffer,oldcrc) * unsigned int buffsize; <==== "equivalent to that" * char *buffer; * unsigned int oldsum; */ #asm arccalc_: call popargs ; registers: CB == Count (yes, backwards) ; DE == Pointer ; HL == OldCrc ; EXX ; get the prime registers lxi d,arctable ; preload address of table EXX ; and back to our main registers mov a,b ; Get count LSB ora a ; is it a zero? jnz arcloop ; nope dcr c ; yes, correct initial-condition anomaly where ; zero == 256 in DJNZ parlance..... arcloop: ldax d ; get data byte xra l ; A == ( crc & 0xff) ^ data EXX ; save all our counters and junk mov l,a ; mvi h,0 ; HL == (short) (( crc & 0xff) ^ data) dad h ; mult by two "sizeof(short)" dad d ; calculate addr of "our" entry mov a,m ; put LSB into AF EXAF ; inx h mov a,m ; put MSB into AF-prime EXX ; get back counter, orig crc & junk EXAF ; get LSB again xra h ; A = LSB ^ crc>>8 mov l,a ; becomes "new" LSB EXAF ; get lookups MSB mov h,a ; and make it our new MSB, HL == new CRC inx d ; update pointer for next time more: DJNZ ; db (arcloop-more)-2 ; loop for the LSB of the count (IN *B* ) mov a,c ; get msb dcr c ; pre-decrement-extend just in case ora a ; is count msb a zero also? jnz arcloop ; nope, go do another 256 loops jmp alldone #endasm /* * Calculate crck on a buffer. Uses the same polynomial as the popular * "ARC" archive program. * * Buffsize is really "valid-data-size", and must be >= 1. * * This routine ignores CR's in the data, and increments CR count in * global variable "Crcount" by the number of CR's found. * * returns: "new" crck calculation -Mike Kersenbrock * tektronix!copper!michaelk * * arcnocr(buffsize,buffer,oldcrc) * unsigned int buffsize; <==== "equivalent to that" * char *buffer; * unsigned int oldsum; */ #asm arcnocr_: call popargs ; ; registers: CB == Count (yes, backwards) ; DE == Pointer ; HL == OldCrc ; EXX ; get the prime registers lxi d,arctable ; preload address of table EXX ; and back to our main registers mov a,b ; Get count LSB ora a ; is it a zero? jnz arcnoloop ; nope dcr c ; yes, correct initial-condition anomaly where ; zero == 256 in DJNZ parlance..... arcnoloop: ldax d ; get data byte cpi 0dh ; CR? jnz doarc ; nope, continue on inx d ; yep, so update pointer EXX ; swap whole register set BC,DE,HL lhld Crcount_ ; get CR counter inx h ; count the CR shld Crcount_ ; restore CR counter EXX ; get "regular" registers back jmp nomore ; and continue on with loop doarc: xra l ; A == ( crc & 0xff) ^ data EXX ; save all our counters and junk mov l,a ; mvi h,0 ; HL == (short) (( crc & 0xff) ^ data) dad h ; mult by two "sizeof(short)" dad d ; calculate addr of "our" entry mov a,m ; put LSB into AF EXAF ; inx h mov a,m ; put MSB into AF-prime EXX ; get back counter, orig crc & junk EXAF ; get LSB again xra h ; A = LSB ^ crc>>8 mov l,a ; becomes "new" LSB EXAF ; get lookups MSB mov h,a ; and make it our new MSB, HL == new CRC inx d ; update pointer for next time nomore: DJNZ ; db (arcnoloop-nomore)-2 ; loop for the LSB of the count (IN *B* ) mov a,c ; get msb dcr c ; pre-decrement-extend just in case ora a ; is count msb a zero also? jnz arcnoloop ; nope, go do another 256 loops jmp alldone arctable: dw 0h,0c0c1h,0c181h,140h,0c301h,3c0h,280h,0c241h dw 0c601h,6c0h,780h,0c741h,500h,0c5c1h,0c481h,440h dw 0cc01h,0cc0h,0d80h,0cd41h,0f00h,0cfc1h,0ce81h,0e40h dw 0a00h,0cac1h,0cb81h,0b40h,0c901h,9c0h,880h,0c841h dw 0d801h,18c0h,1980h,0d941h,1b00h,0dbc1h,0da81h,1a40h dw 1e00h,0dec1h,0df81h,1f40h,0dd01h,1dc0h,1c80h,0dc41h dw 1400h,0d4c1h,0d581h,1540h,0d701h,17c0h,1680h,0d641h dw 0d201h,12c0h,1380h,0d341h,1100h,0d1c1h,0d081h,1040h dw 0f001h,30c0h,3180h,0f141h,3300h,0f3c1h,0f281h,3240h dw 3600h,0f6c1h,0f781h,3740h,0f501h,35c0h,3480h,0f441h dw 3c00h,0fcc1h,0fd81h,3d40h,0ff01h,3fc0h,3e80h,0fe41h dw 0fa01h,3ac0h,3b80h,0fb41h,3900h,0f9c1h,0f881h,3840h dw 2800h,0e8c1h,0e981h,2940h,0eb01h,2bc0h,2a80h,0ea41h dw 0ee01h,2ec0h,2f80h,0ef41h,2d00h,0edc1h,0ec81h,2c40h dw 0e401h,24c0h,2580h,0e541h,2700h,0e7c1h,0e681h,2640h dw 2200h,0e2c1h,0e381h,2340h,0e101h,21c0h,2080h,0e041h dw 0a001h,60c0h,6180h,0a141h,6300h,0a3c1h,0a281h,6240h dw 6600h,0a6c1h,0a781h,6740h,0a501h,65c0h,6480h,0a441h dw 6c00h,0acc1h,0ad81h,6d40h,0af01h,6fc0h,6e80h,0ae41h dw 0aa01h,6ac0h,6b80h,0ab41h,6900h,0a9c1h,0a881h,6840h dw 7800h,0b8c1h,0b981h,7940h,0bb01h,7bc0h,7a80h,0ba41h dw 0be01h,7ec0h,7f80h,0bf41h,7d00h,0bdc1h,0bc81h,7c40h dw 0b401h,74c0h,7580h,0b541h,7700h,0b7c1h,0b681h,7640h dw 7200h,0b2c1h,0b381h,7340h,0b101h,71c0h,7080h,0b041h dw 5000h,90c1h,9181h,5140h,9301h,53c0h,5280h,9241h dw 9601h,56c0h,5780h,9741h,5500h,95c1h,9481h,5440h dw 9c01h,5cc0h,5d80h,9d41h,5f00h,9fc1h,9e81h,5e40h dw 5a00h,9ac1h,9b81h,5b40h,9901h,59c0h,5880h,9841h dw 8801h,48c0h,4980h,8941h,4b00h,8bc1h,8a81h,4a40h dw 4e00h,8ec1h,8f81h,4f40h,8d01h,4dc0h,4c80h,8c41h dw 4400h,84c1h,8581h,4540h,8701h,47c0h,4680h,8641h dw 8201h,42c0h,4380h,8341h,4100h,81c1h,8081h,4040h #endasm /* * Calculate crck on a buffer. Uses the same polynomial as the * CCITCRC program, or the LU/XMODEM program, depending upon * the called initial value and the contents of "Table". * * Buffsize is really "valid-data-size", and must be >= 1. * * returns: "new" crc calculation -Mike Kersenbrock * tektronix!copper!michaelk * * gpcalc(buffsize,buffer,oldcrc) * unsigned int buffsize; <==== "equivalent to that" * char *buffer; * unsigned int oldsum; */ #asm gpcalc_: call popargs ; ; registers: CB == Count (yes, backwards) ; DE == Pointer ; HL == OldCrc ; EXX ; get prime registers LDED ; preload table address dw Table_; EXX ; back to regular registers mov a,b ; Get count LSB ora a ; is it a zero? jnz gploop ; nope dcr c ; yes, correct initial-condition anomaly where ; zero == 256 in DJNZ parlance..... gploop: ldax d ; get data byte xra h ; A == (char) ((crc>>8) ^ data) EXX ; save all our counters and junk mov l,a ; mvi h,0 ; HL == (short) ((crc>>8) ^ data) dad h ; mult by two "sizeof(short)" dad d ; calculate addr of "our" entry mov a,m ; put LSB into AF EXAF ; inx h mov a,m ; put MSB into AF-prime EXX ; get back counter, orig crc & junk xra l ; A = MSB ^ crc<<8 mov h,a ; becomes "new" MSB EXAF ; get lookups LSB mov l,a ; and make it our new LSB, HL == new CRC inx d ; update pointer for next time gpmore: DJNZ ; db (gploop-gpmore)-2 ; loop for the LSB of the count (IN *B* ) mov a,c ; get msb dcr c ; pre-decrement-extend just in case ora a ; is count msb a zero also? jnz gploop ; nope, go do another 256 loops jmp alldone /* * Calculate crck on a buffer. Uses the same polynomial as the * CCITCRC program, or the LU/XMODEM program, depending upon * the called initial value and the contents of "Table". * * Buffsize is really "valid-data-size", and must be >= 1. * * This routine ignores CR's in the data, and increments CR count in * global variable "Crcount" by the number of CR's found. * * returns: "new" crck calculation -Mike Kersenbrock * tektronix!copper!michaelk * * gpnocr(buffsize,buffer,oldcrc) * unsigned int buffsize; <==== "equivalent to that" * char *buffer; * unsigned int oldsum; */ gpnocr_: call popargs ; registers: CB == Count (yes, backwards) ; DE == Pointer ; HL == OldCrc ; EXX ; get prime registers LDED ; preload table address dw Table_ ; EXX ; back to regular registers mov a,b ; Get count LSB ora a ; is it a zero? jnz gpnoloop ; nope dcr c ; yes, correct initial-condition anomaly where ; zero == 256 in DJNZ parlance..... gpnoloop: ldax d ; get data byte cpi 0dh ; CR? jnz dogp ; nope, continue on inx d ; yep, so update pointer EXX ; swap whole register set BC,DE,HL lhld Crcount_ ; get CR counter inx h ; count the CR shld Crcount_ ; restore CR counter EXX ; get "regular" registers back jmp gpnomore ; and continue on with loop dogp: xra h ; A == (char) ((crc>>8) ^ data) EXX ; save all our counters and junk mov l,a ; mvi h,0 ; HL == (short) ((crc>>8) ^ data) dad h ; mult by two "sizeof(short)" dad d ; calculate addr of "our" entry mov a,m ; put LSB into AF EXAF ; inx h mov a,m ; put MSB into AF-prime EXX ; get back counter, orig crc & junk xra l ; A = MSB ^ crc<<8 mov h,a ; becomes "new" MSB EXAF ; get lookups LSB mov l,a ; and make it our new LSB, HL == new CRC inx d ; update pointer for next time gpnomore: DJNZ ; db (gpnoloop-gpnomore)-2 ; loop for the LSB of the count (IN *B* ) mov a,c ; get msb dcr c ; pre-decrement-extend just in case ora a ; is count msb a zero also? jnz gpnoloop ; nope, go do another 256 loops jmp alldone cctable_: dw 0h,0a097h,0e1b9h,412eh,63e5h,0c372h,825ch,22cbh dw 0c7cah,675dh,2673h,86e4h,0a42fh,4b8h,4596h,0e501h dw 2f03h,8f94h,0cebah,6e2dh,4ce6h,0ec71h,0ad5fh,0dc8h dw 0e8c9h,485eh,970h,0a9e7h,8b2ch,2bbbh,6a95h,0ca02h dw 5e06h,0fe91h,0bfbfh,1f28h,3de3h,9d74h,0dc5ah,7ccdh dw 99cch,395bh,7875h,0d8e2h,0fa29h,5abeh,1b90h,0bb07h dw 7105h,0d192h,90bch,302bh,12e0h,0b277h,0f359h,53ceh dw 0b6cfh,1658h,5776h,0f7e1h,0d52ah,75bdh,3493h,9404h dw 0bc0ch,1c9bh,5db5h,0fd22h,0dfe9h,7f7eh,3e50h,9ec7h dw 7bc6h,0db51h,9a7fh,3ae8h,1823h,0b8b4h,0f99ah,590dh dw 930fh,3398h,72b6h,0d221h,0f0eah,507dh,1153h,0b1c4h dw 54c5h,0f452h,0b57ch,15ebh,3720h,97b7h,0d699h,760eh dw 0e20ah,429dh,3b3h,0a324h,81efh,2178h,6056h,0c0c1h dw 25c0h,8557h,0c479h,64eeh,4625h,0e6b2h,0a79ch,70bh dw 0cd09h,6d9eh,2cb0h,8c27h,0aeech,0e7bh,4f55h,0efc2h dw 0ac3h,0aa54h,0eb7ah,4bedh,6926h,0c9b1h,889fh,2808h dw 0d88fh,7818h,3936h,99a1h,0bb6ah,1bfdh,5ad3h,0fa44h dw 1f45h,0bfd2h,0fefch,5e6bh,7ca0h,0dc37h,9d19h,3d8eh dw 0f78ch,571bh,1635h,0b6a2h,9469h,34feh,75d0h,0d547h dw 3046h,90d1h,0d1ffh,7168h,53a3h,0f334h,0b21ah,128dh dw 8689h,261eh,6730h,0c7a7h,0e56ch,45fbh,4d5h,0a442h dw 4143h,0e1d4h,0a0fah,6dh,22a6h,8231h,0c31fh,6388h dw 0a98ah,91dh,4833h,0e8a4h,0ca6fh,6af8h,2bd6h,8b41h dw 6e40h,0ced7h,8ff9h,2f6eh,0da5h,0ad32h,0ec1ch,4c8bh dw 6483h,0c414h,853ah,25adh,766h,0a7f1h,0e6dfh,4648h dw 0a349h,3deh,42f0h,0e267h,0c0ach,603bh,2115h,8182h dw 4b80h,0eb17h,0aa39h,0aaeh,2865h,88f2h,0c9dch,694bh dw 8c4ah,2cddh,6df3h,0cd64h,0efafh,4f38h,0e16h,0ae81h dw 3a85h,9a12h,0db3ch,7babh,5960h,0f9f7h,0b8d9h,184eh dw 0fd4fh,5dd8h,1cf6h,0bc61h,9eaah,3e3dh,7f13h,0df84h dw 1586h,0b511h,0f43fh,54a8h,7663h,0d6f4h,97dah,374dh dw 0d24ch,72dbh,33f5h,9362h,0b1a9h,113eh,5010h,0f087h #endasm printmode(stream) int stream; { fprintf(stream, "\nCRCK(K) Universal CRC program\t\t\tMike Kersenbrock Aloha,Oregon\n"); fprintf(stream,"Version %1d.%1d\n\n", VERSION/10, VERSION%10); if (uflag) fprintf(stream,"Unix-text simulation mode selected\n"); if (tflag) fprintf(stream,"CP/M text mode selected\n"); if (cflag) fprintf(stream,"CP/M binary mode w/sector count selected\n"); if (bflag) fprintf(stream,"CP/M binary file mode selected\n"); if (aflag) fprintf(stream,"\nARC compatible CRC mode selected\n"); if (sflag) fprintf(stream,"\nCCITCRC compatible CRC mode selected\n"); if (lflag) fprintf(stream,"\nLU compatible CRC mode selected\n"); putc('\n',stream); } #asm lutable_: dw 0h,1021h,2042h,3063h,4084h,50a5h,60c6h,70e7h dw 8108h,9129h,0a14ah,0b16bh,0c18ch,0d1adh,0e1ceh,0f1efh dw 1231h,210h,3273h,2252h,52b5h,4294h,72f7h,62d6h dw 9339h,8318h,0b37bh,0a35ah,0d3bdh,0c39ch,0f3ffh,0e3deh dw 2462h,3443h,420h,1401h,64e6h,74c7h,44a4h,5485h dw 0a56ah,0b54bh,8528h,9509h,0e5eeh,0f5cfh,0c5ach,0d58dh dw 3653h,2672h,1611h,630h,76d7h,66f6h,5695h,46b4h dw 0b75bh,0a77ah,9719h,8738h,0f7dfh,0e7feh,0d79dh,0c7bch dw 48c4h,58e5h,6886h,78a7h,840h,1861h,2802h,3823h dw 0c9cch,0d9edh,0e98eh,0f9afh,8948h,9969h,0a90ah,0b92bh dw 5af5h,4ad4h,7ab7h,6a96h,1a71h,0a50h,3a33h,2a12h dw 0dbfdh,0cbdch,0fbbfh,0eb9eh,9b79h,8b58h,0bb3bh,0ab1ah dw 6ca6h,7c87h,4ce4h,5cc5h,2c22h,3c03h,0c60h,1c41h dw 0edaeh,0fd8fh,0cdech,0ddcdh,0ad2ah,0bd0bh,8d68h,9d49h dw 7e97h,6eb6h,5ed5h,4ef4h,3e13h,2e32h,1e51h,0e70h dw 0ff9fh,0efbeh,0dfddh,0cffch,0bf1bh,0af3ah,9f59h,8f78h dw 9188h,81a9h,0b1cah,0a1ebh,0d10ch,0c12dh,0f14eh,0e16fh dw 1080h,0a1h,30c2h,20e3h,5004h,4025h,7046h,6067h dw 83b9h,9398h,0a3fbh,0b3dah,0c33dh,0d31ch,0e37fh,0f35eh dw 2b1h,1290h,22f3h,32d2h,4235h,5214h,6277h,7256h dw 0b5eah,0a5cbh,95a8h,8589h,0f56eh,0e54fh,0d52ch,0c50dh dw 34e2h,24c3h,14a0h,481h,7466h,6447h,5424h,4405h dw 0a7dbh,0b7fah,8799h,97b8h,0e75fh,0f77eh,0c71dh,0d73ch dw 26d3h,36f2h,691h,16b0h,6657h,7676h,4615h,5634h dw 0d94ch,0c96dh,0f90eh,0e92fh,99c8h,89e9h,0b98ah,0a9abh dw 5844h,4865h,7806h,6827h,18c0h,8e1h,3882h,28a3h dw 0cb7dh,0db5ch,0eb3fh,0fb1eh,8bf9h,9bd8h,0abbbh,0bb9ah dw 4a75h,5a54h,6a37h,7a16h,0af1h,1ad0h,2ab3h,3a92h dw 0fd2eh,0ed0fh,0dd6ch,0cd4dh,0bdaah,0ad8bh,9de8h,8dc9h dw 7c26h,6c07h,5c64h,4c45h,3ca2h,2c83h,1ce0h,0cc1h dw 0ef1fh,0ff3eh,0cf5dh,0df7ch,0af9bh,0bfbah,8fd9h,9ff8h dw 6e17h,7e36h,4e55h,5e74h,2e93h,3eb2h,0ed1h,1ef0h ; ; Common calling parameter "popping" proceedure for the ; "C"-callable assembly language routines. See the header of ; each routine where this is called for the resulting format. ; Note that upon return, the BC register is still on stack (it will ; be restored upon routine exit -- BC is a register variable). ; popargs: lxi h,4 ; offset "around" return addresses dad sp ; point at the first arguement on stack pop d ; get return value for a second push b ; save register variable bc at proper place push d ; put return address back on stack mov b,m inx h mov c,m ; buffsize is now in CB (yes, backwards) inx h mov e,m inx h mov d,m push d ; buffer pointer is now at top-of-stack inx h mov e,m inx h mov d,m ; oldcrc is now in DE pop h ; get pointer to buffer into HL xchg ret #endasm