home *** CD-ROM | disk | FTP | other *** search
-
- ; CRCK.ASM Version 5.1 (Originally by: Keith Petersen, W8SDZ)
- ;
- ; CRCK is a program to read any CP/M file and print a cyclic-
- ; redundancy-check number based on the CCITT standard polynominal:
- ;
- ; x^16 + x^15 + x^13 + x^7 + x^4 + x^2 + x + 1
- ;
- ; Useful for checking accuracy of file transfers, and more accurate
- ; than a simple checksum. Optionally will write an output file to
- ; the default drive, listing the CRC's of all files checked in a
- ; single session.
- ;
- ; Commands: crck [drive:]<filename.filetype> [f]<cr>
- ;
- ; Examples:
- ;
- ; crck myfile.asm<cr> (check only myfile.asm)
- ; crck *.asm<cr> (check all .asm files
- ; crck *.* f<cr> (check all files, make file of results)
- ;
- ;
- ; Program updates/fixes (these are written in reverse order to
- ; minimize reading time to find latest update):
- ;
- ; 04/10/82 version 5.1, Kelly Smith
- ;
- ; Removed requirement for MAC.ASM and SEQIO.LIB for assembly
- ;
- ; 11/27/81 version 5.0, Dave Barker
- ;
- ; All earlier versions of CRCK.ASM (up to at least Ver. 4.2 of
- ; 10/06/80) seen by this writer (DAB) have a serious flaw in the
- ; algorithm used to generate the CRC value. Mr. Petersen used a
- ; routine from "EDN" magazine, June 5, 1979. Although the routine
- ; published in EDN was a workable one, the way in which it was
- ; applied in CRCK.ASM was incorrect (i.e. the routine should have
- ; been called 8 times per byte, each time with only one bit of the
- ; message in the A register, then, at the end of the file, 2 null
- ; bytes should have been processed as if they were part of the
- ; file). The method that is used in CRCK.ASM Version 5.0 is a table
- ; lookup method. Instead of calling a routine 8 times each byte of
- ; the message is processed in one short piece of straight line
- ; code. The table that is used in this method is first generated
- ; during initialization.
- ;
- ; - Validity -
- ;
- ; Version 5.0 generates exactly the same CRC value that the earlier
- ; versions would have generated if they had correctly used the
- ; algorithm. The message (the file) is processed in the order: MS
- ; bit of the MS byte first (if the file were to be processed as a
- ; serial data transmission, then the LS bit of the MS byte would
- ; come first --> the order in which it is transmitted through a
- ; UART).
- ;
- ; Note: Usually, the CRC of a message is appended to the end of a
- ; message when it is sent. This causes the resultant CRC at the
- ; receiving end to be zero (this is the reason that the 2 dummy
- ; null bytes are added to the end of the message when the CRC is
- ; generated or checked).
- ;
- ;
- ;
- ; define true and false
- ;
- false EQU 0
- true EQU not false
- ;
- ; conditional assembly switches
- ;
- stdcpm EQU true ; true is standard cp/m
- altcpm EQU false ; true is h8 or trs-80
- nosys EQU false ; true if sys files not wanted
- ;
- M EQU Byte Ptr 0[BX]
- ;
- ; system equates
- ;
- base EQU 0
- ;
- ; define write buffer size (presently set for 8k)
- ;
- bsize EQU 8*1024 ; disk write buffer size
- ;
- ; bdos equates
- ;
- rdcon EQU 1
- wrcon EQU 2
- print EQU 9
- cstat EQU 11
- open EQU 15
- close EQU 16
- srchf EQU 17
- srchn EQU 18
- delet EQU 19
- read EQU 20
- write EQU 21
- make EQU 22
- renam EQU 23
- stdma EQU 26
- stbas EQU 51
- ;
- bdos EQU base+5
- ;
- fcb EQU base+5ch
- fcbext EQU fcb+12
- fcbrno EQU fcb+32
- fcb2 EQU base+6ch
- ;
- tbuf EQU base+80h ; temporary buffer (default) address
- buf@siz EQU 80h ; buffer size (128 bytes)
- ;
- crcfilesiz EQU 2000h
- ;
- tab EQU 09h ; tab character
- lf EQU 0ah ; line feed character
- cr EQU 0dh ; carriage return character
- eof EQU 'Z'-40h ; end-of-file character
- ;
- ; CCIT CRC polynomial mask bytes
- ;
- himsk EQU 0a0h ; high mask byte
- lomsk EQU 097h ; low mask byte
- ;
- ;
- ;
- ; program starts here
- ;
- ORG base+100h
- ;
- begin: MOV SP,(offset stktop) ; make local stack
- CALL crlf ; turn up a new line
- MOV AL,Byte Ptr .fcb+1
- CMP AL,' ' ; see if name there
- JNZ begin2 ; yes, continue
- CALL erxit ; print msg, then exit
- DB '++No File Name Specified++',cr,lf,'$'
- ;
- begin2: CALL ilprt ; print:
- DB '--------- CRCK Ver 5.1 ---------'
- DB cr,lf
- DB 'CTRL-S to Pause, CTRL-C to Abort'
- DB cr,lf,cr,lf,0
- ;
- ; generate the lookup table for fast crc
- ;
- MOV BX,(Offset hitab)
- MOV CL,0 ; the table index
- gloop: XCHG BX,DX
- MOV BX,0 ; init the crc
- MOV AL,CL
- CALL lcrc
- XCHG BX,DX ; de now has the crc, hl pointing into table
- MOV M,DH ; store the high byte of crc
- INC BH
- MOV M,DL ; store the low byte
- DEC BH
- INC BX ; move to next table entry
- INC CL ; next index
- JNZ gloop
- MOV AL,Byte Ptr .fcb2+1 ; get option
- MOV Byte Ptr fflag,AL ; save it for later
- CMP AL,'F' ; file wanted?
- JZ L_1
- JMP again ; no, skip file init
- L_1:
- XOR AL,AL
- MOV Byte Ptr fcbcrcfile+12,AL ; clear extent
- MOV Byte Ptr fcbcrcfile+32,AL ; clear current record count
- MOV BX,crcfilesiz ; set buffer size
- MOV Word Ptr crcfilelen,BX
- MOV BX,0 ; set next to fill
- MOV Word Ptr crcfileptr,BX
- MOV CL,delet ; delete file function
- MOV DX,(Offset fcbcrcfile) ; delete 'old' crcklist file
- INT 224
- MOV CL,make ; make file function
- MOV DX,(Offset fcbcrcfile) ; make 'new' crcklist file
- INT 224
- INC AL ; make ok?
- JZ L_2
- JMP again
- L_2:
- MOV CL,print ; print string function
- MOV DX,(Offset dir@full) ; indicate that directory is full
- INT 224
- JMP filerr
- ;
- ;
- ;
- putcrcfile:
- ;
- LAHF ; save output character
- XCHG AL,AH
- PUSH AX
- MOV BX,Word Ptr crcfilelen ; get current buffer length
- XCHG BX,DX ; de has length
- MOV BX,Word Ptr crcfileptr ; load next to get/put to hl
- MOV AL,BL ; compute current length
- SUB AL,DL
- MOV AL,BH
- SBB AL,DH ; carry if next < length
- JB putcrc4 ; carry if length > current
- MOV BX,0 ; end of buffer, fill (empty) buffers
- MOV Word Ptr crcfileptr,BX ; clear next to get/put
- ;
- putcrc1: ; process next disk sector
- ;
- XCHG BX,DX ; file pointer to de
- MOV BX,Word Ptr crcfilelen ; hl is maximum buffer length
- MOV AL,DL ; compute next length
- SUB AL,BL ; to get carry, if more fill
- MOV AL,DH
- SBB AL,BH
- JNB putcrc3
- MOV BX,Word Ptr crcfileadr ; got carry, more to fill yet
- ADD BX,DX ; hl is next buffer address
- XCHG BX,DX
- MOV CL,stdma ; set dma address
- INT 224
- MOV CL,stbas ; set dma base
- MOV DX,DS
- INT 224
- MOV DX,(Offset fcbcrcfile) ; fcb address to de
- MOV CL,write ; file write
- INT 224
- OR AL,AL ; check return code
- JNZ putcrc2 ; end-of-file yet?
- MOV DX,buf@siz ; not eof, increment length by 128
- MOV BX,Word Ptr crcfileptr ; next to fill
- ADD BX,DX
- MOV Word Ptr crcfileptr,BX ; save new pointer
- JMPS putcrc1 ; process another sector
- ;
- putcrc2: ; got end-of-file
- ;
- MOV CL,print ; print string function
- MOV DX,(Offset dsk@full) ; disk is full
- INT 224
- POP AX ; clean stack
- XCHG AL,AH
- JMP filerr ; file error, exit
- ;
- putcrc3: ; end of buffer, reset dma and pointer
- ;
- MOV DX,tbuf ; point to temporary buffer
- MOV CL,stdma ; set dma function
- INT 224
- MOV CL,stbas ; set dma base
- MOV DX,DS
- INT 224
- MOV BX,0 ; reset pointer for next to get
- MOV Word Ptr crcfileptr,BX
- ;
- putcrc4: ; process the next character
- ;
- XCHG BX,DX ; index to get/put in de
- MOV BX,Word Ptr crcfileadr ; base of buffer
- ADD BX,DX ; address of character in hl
- XCHG BX,DX ; and swap to de
- POP AX ; get save character
- XCHG AL,AH
- SAHF
- MOV DI,DX ; character to buffer
- MOV [DI],AL
- MOV BX,Word Ptr crcfileptr ; index to get/put
- LAHF ; and update for next character
- INC BX
- SAHF
- MOV Word Ptr crcfileptr,BX
- RET
- ;
- again: MOV SP,(offset stktop) ; make local stack
- CALL mfname ; search for names
- JNAE L_3
- JMP namtst ; another found, print name
- L_3:
- MOV AL,Byte Ptr mfflg1 ; nothing found, check...
- OR AL,AL ; ... first time flag
- JZ done ; at least one was found
- CALL abexit ; print msg, then exit
- DB '++File Not Found++$'
- ;
- done: MOV AL,Byte Ptr fflag ; see if we're making file
- CMP AL,'F'
- JNZ done2 ; no, skip the file stuff
- ;
- ; close crcklist.$$$
- ;
- closecrc:
- ;
- MOV BX,Word Ptr crcfileptr
- MOV AL,BL
- AND AL,07fh
- JNZ close1
- MOV Word Ptr crcfilelen,BX
- close1: MOV AL,eof
- LAHF
- XCHG AL,AH
- PUSH AX
- XCHG AL,AH
- CALL putcrcfile
- POP AX
- XCHG AL,AH
- SAHF
- JNZ closecrc
- MOV CL,close
- MOV DX,(Offset fcbcrcfile)
- INT 224
- INC AL
- JNZ erase
- MOV CL,print
- MOV DX,(Offset no@close)
- INT 224
- ;
- ; erase any existing old file
- ;
- erase: MOV CL,delet
- MOV DX,(Offset fcbfinal)
- INT 224
- ;
- ; rename crcklist.$$$ to crcklist.crc
- ;
- MOV BX,(Offset fcbcrcfile)
- MOV DX,(Offset fcbfinal)
- PUSH BX
- MOV CX,16
- LAHF
- ADD BX,CX
- RCR SI,1
- SAHF
- RCL SI,1
- ;
- mov@name:
- ;
- MOV SI,DX
- MOV AL,[SI]
- MOV M,AL
- LAHF
- INC DX
- SAHF
- LAHF
- INC BX
- SAHF
- DEC CL
- JNZ mov@name
- POP DX
- MOV CL,renam
- INT 224
- ;
- ; now exit to cp/m
- ;
- done2: CALL erxit ; print done, then exit
- DB cr,lf,'Done$'
- ;
- ; test for names to ignore
- ;
- namtst:
- ;
- if nosys ; if $SYS file, ignore it
- MOV AL,Byte Ptr .fcb+10 ; get $SYS file attribute
- AND AL,080h ; is it $SYS?
- JNZ again ; yes, ignore this file
- endif ; nosys
- ;
- ; ignore files with .$$$ filetype (they are usually
- ; zero-length and clutter up our display. we also
- ; want to ignore our own crcklist.$$$ temporary file).
- ;
- MOV BX,fcb+9 ; point to filetype in fcb
- CALL tstbad ; check for .$$$ files
- JNZ L_4
- JMP again ; if zero flag, ignore them
- L_4:
- ;
- ; move 8 characters from fcb+1 to fname
- ;
- MOV BX,fcb+1
- MOV DX,(Offset fname)
- MOV CX,8
- CALL mover
- ;
- ; move 3 characters from fcb+9 to fname+9
- ;
- MOV BX,fcb+9
- MOV DX,(Offset fname)+9
- MOV CX,3
- CALL mover
- ;
- ; now print filename.type
- ;
- CALL ilprt ; print:
- ;
- fname DB 'xxxxxxxx.xxx',tab,'CRC = ',0
- ;
- ; open the file
- ;
- MOV DX,fcb
- MOV CL,open
- INT 224
- INC AL
- JNZ rdinit
- CALL abexit
- DB '++Open Failed++$'
- ;
- ; initialize crc to zero and set bufad to cause initial read
- ;
- rdinit: MOV BX,0
- MOV Word Ptr rem,BX ; init remainder to zero
- MOV BX,base+100h
- MOV Word Ptr bufad,BX ; init buffer adrs
- ;
- ; this is the read loop
- ;
- readit: MOV BX,Word Ptr bufad
- MOV AL,BH ; time to read?
- CMP AL,base shr 8
- JZ nord ; no read
- MOV CL,cstat
- INT 224 ; check for operator abort
- OR AL,AL
- JZ read2 ; nothing from operator
- MOV CL,rdcon
- INT 224 ; get character inputted
- CMP AL,'C'-40h ; control c?
- JNZ L_5
- JMP abext2 ; yes exit
- L_5:
- ;
- read2: MOV DX,fcb
- MOV CL,read ; read another sector of file
- INT 224
- OR AL,AL ; check return code
- JNZ finish ; error or eof
- MOV BX,tbuf ; buffer location
- ;
- nord: MOV AL,M ; get file character
- INC BX
- MOV Word Ptr bufad,BX
- MOV BX,Word Ptr rem ; pick up the partial remainder
- ;
- ; table lookup method for crc generation
- ;
- XCHG BX,DX ; de now has the partial
- MOV CH,0
- XOR AL,DH
- MOV CL,AL
- MOV BX,(Offset hitab)
- ADD BX,CX
- MOV AL,M
- XOR AL,DL
- MOV DH,AL
- INC BH
- MOV DL,M
- XCHG BX,DX
- MOV Word Ptr rem,BX
- JMPS readit ; go read more characters
- ;
- ;
- ;
- finish: CMP AL,1 ; normal end-of-file?
- JNZ filerr ; no, it was a read error
- MOV AL,Byte Ptr rem+1 ; get msp of crc
- CALL hexo ; print it
- MOV AL,Byte Ptr rem ; get lsp of crc
- CALL hexo ; print it
- CALL crlf ; turn up new line
- JMP again ; see if more files to do
- ;
- filerr: CALL abexit ; abort because of file read error
- DB '++File Read Error++$'
- ;
- ; hl contains the partial, a the character to be crc'd
- ;
- lcrc: PUSH CX
- MOV CH,8
- XOR AL,BH
- MOV BH,AL
- loop: SHL BX,1
- JNB skip
- MOV AL,himsk
- XOR AL,BH
- MOV BH,AL
- MOV AL,lomsk
- XOR AL,BL
- MOV BL,AL
- skip: DEC CH
- JNZ loop
- POP CX
- RET
- ;
- ; hex output
- ;
- hexo: LAHF ; save for right digit
- XCHG AL,AH
- PUSH AX
- XCHG AL,AH
- RCR AL,1 ; right..
- RCR AL,1 ; ..justify..
- RCR AL,1 ; ..left..
- RCR AL,1 ; ..digit..
- CALL nibbl ; print left digit
- POP AX ; restore right
- XCHG AL,AH
- ;
- nibbl: AND AL,0fh ; isolate digit
- CMP AL,10 ; is is <10?
- JB isnum ; yes, not alpha
- ADD AL,7 ; add alpha bias
- ;
- isnum: ADD AL,'0' ; make printable
- JMPS display ; print it, then return
- ;
- ;
- ;
- ; inline print routine
- ;
- ilprt: MOV BP,SP ; save hl, get msg
- XCHG BX,[BP]
- ;
- ilplp: MOV AL,M ; get char
- CALL display ; output it
- INC BX ; point to next
- MOV AL,M ; test
- OR AL,AL ; ..for end
- JNZ ilplp
- INC BX ; bump pointer for return address
- MOV BP,SP ; restore hl, ret addr
- XCHG BX,[BP]
- RET ; ret past msg
- ;
- ;
- ;
- ; send carriage return, line feed to output
- ;
- crlf: MOV AL,cr ; carriage return
- CALL display
- MOV AL,lf ; line feed, fall into 'type'
- ;
- ; send character in a register to output
- ;
- display:
- ;
- PUSH CX
- PUSH DX
- PUSH BX
- AND AL,7fh ; strip parity bit
- MOV DL,AL
- PUSH DX
- CALL wrfile ; write to file if requested
- POP DX
- MOV CL,wrcon ; send character to console
- INT 224
- POP BX
- POP DX
- POP CX
- RET
- ;
- ;
- ;
- ; write character in e register to output file
- ;
- wrfile: MOV AL,Byte Ptr fflag ; get file trigger
- CMP AL,'F' ; is it set?
- JZ L_6
- RET ; no, return
- L_6:
- MOV AL,DL ; get character back
- CALL putcrcfile
- RET
- ;
- ; multi-file access subroutine. allows processing
- ; of multiple files (i.e. *.asm) from disk. this
- ; routine builds the proper name in the fcb each
- ; time it is called. carry is set if no more names
- ; can be found.
- ;
- mfname: ; init dma addr and fcb
- MOV CL,stdma
- MOV DX,tbuf
- INT 224
- MOV CL,stbas ; set dma base
- MOV DX,DS
- INT 224
- XOR AL,AL
- MOV Byte Ptr .fcbext,AL
- MOV Byte Ptr .fcbrno,AL
- ;
- ; if first time
- ;
- MOV AL,Byte Ptr mfflg1
- OR AL,AL
- JZ mfn01
- ;
- ; save the requested name
- ;
- MOV BX,fcb
- MOV DX,(Offset mfreq)
- MOV CX,12
- CALL mover
- MOV AL,Byte Ptr .fcb
- MOV Byte Ptr mfcur,AL ; save disk in curr fcb
- ;
- ; srchf requested name
- ;
- MOV BX,(Offset mfreq)
- MOV DX,fcb
- MOV CX,12
- CALL mover
- MOV CL,srchf
- MOV DX,fcb
- INT 224
- ;
- ; else
- ;
- JMPS mfn02
- ;
- mfn01: ; srchf current name
- MOV BX,(Offset mfcur)
- MOV DX,fcb
- MOV CX,12
- CALL mover
- MOV CL,srchf
- MOV DX,fcb
- INT 224
- ;
- ; srchn requested name
- ;
- MOV BX,(Offset mfreq)
- MOV DX,fcb
- MOV CX,12
- CALL mover
- MOV CL,srchn
- MOV DX,fcb
- INT 224
- ;
- ; endif
- ;
- mfn02: ; return carry if not found
- INC AL
- STC
- JNZ L_7
- RET
- L_7:
- ;
- ; move name found to current name
- ;
- DEC AL
- AND AL,3
- ADD AL,AL
- ADD AL,AL
- ADD AL,AL
- ADD AL,AL
- ADD AL,AL
- ADD AL,81h
- MOV BL,AL
- MOV BH,0
- PUSH BX ; save name pointer
- MOV DX,(Offset mfcur)+1
- MOV CX,11
- CALL mover
- ;
- ; move name found to fcb
- ;
- POP BX
- MOV DX,fcb+1
- MOV CX,11
- CALL mover
- ;
- ; setup fcb
- ;
- XOR AL,AL
- MOV Byte Ptr .fcbext,AL
- MOV Byte Ptr .fcbrno,AL
- MOV Byte Ptr mfflg1,AL ; turn off 1st time sw
- RET
- ;
- ;
- ;
- ; check for .$$$ files
- ;
- tstbad: CALL testit ; check first one for '$'
- JZ L_8
- RET ; no, return
- L_8:
- CALL testit ; check second one
- JZ L_9
- RET ; no, return
- L_9:
- testit: MOV AL,M
- AND AL,7fh ; strip attribute
- CMP AL,'$' ; check for $ filetype
- LAHF
- INC BX
- SAHF
- RET
- ;
- ;
- ;
- ; move (bc) bytes from (hl) to (de)
- ;
- mover: MOV AL,M
- MOV SI,DX
- MOV [SI],AL
- INC BX
- INC DX
- DEC CX
- MOV AL,CH
- OR AL,CL
- JNZ mover
- RET
- ;
- ;
- ;
- ; aborted - print reason. if making output file,
- ; close the incomplete file to update cp/m's bit map,
- ; then erase it.
- ;
- abexit: POP DX ; get msg adrs
- MOV CL,print
- INT 224 ; print msg
- ;
- abext2: MOV AL,Byte Ptr fflag ; see if we are making file
- CMP AL,'F'
- JNZ abext5 ; no file, skip file stuff
- abext3: MOV BX,Word Ptr crcfileptr
- MOV AL,BL
- AND AL,07fh
- JNZ abext4
- MOV Word Ptr crcfilelen,BX
- abext4: MOV AL,eof
- LAHF
- XCHG AL,AH
- PUSH AX
- XCHG AL,AH
- CALL putcrcfile
- POP AX
- XCHG AL,AH
- SAHF
- JNZ abext3
- MOV CL,close
- MOV DX,(Offset fcbcrcfile)
- INT 224
- INC AL
- JNZ era@crc
- MOV CL,print
- MOV DX,(Offset no@close)
- INT 224
- ;
- ; erase incomplete file
- ;
- era@crc:
- ;
- MOV CL,delet
- MOV DX,(Offset fcbcrcfile)
- INT 224
- ;
- abext5: CALL erxit ; print msg, exit
- DB cr,lf,cr,lf,'++Aborted++$'
- ;
- ; exit with message
- ;
- erxit: POP DX ; get msg
- MOV CL,print
- INT 224
- ;
- ; exit, via system warm boot
- ;
- exit: mov cl,0 ; warm boot to cp/m
- mov dl,0
- int 224
- ;
- ;
- ;
- dir@full DB cr,lf
- DB '++No Directory Space for CRC File++'
- DB '$'
- ;
- dsk@full DB cr,lf
- DB '++No Disk Space for CRC File++'
- DB '$'
- ;
- no@close DB cr,lf
- DB '++Cannot Close CRC File++'
- DB '$'
-
- ;
- ; program storage area
- ;
- RS 64 ; 32 level local stack
- stktop equ $ ; top of local stack
- ;
- fflag DB 0 ; file write request flag
- rem DW 0 ; crc remainder storage
- mess DB 0 ; crc message char goes here
- mfflg1 DB 1 ; 1st time switch
- mfreq RS 12 ; requested name
- mfcur RS 12 ; current name
- bufad RS 2 ; read buffer address
- ;
- hitab RS 512 ; the 2 tables for crc lookup
- ;
- crcfilelen DW crcfilesiz
- ;
- crcfileptr RS 2
- ;
- ; build fcb for final name of crcklist.crc
- ;
- fcbfinal DB 0,'CRCKLISTCRC'
- DB 0
- RS 20
- ;
- ; 'declare' fcb for output file (temporarily named crcklist.$$$)
- ;
- fcbcrcfile DB 0,'CRCKLIST$$$'
- DB 0
- RS 20
- ;
- crcfileadr DW crcfileadr+2 ; buffer all crc file data here
- RS 02000h ; force buffer area
- DB 0 ; tag 'end' for GENCMD
- ;
- ;
- ;
- END
-