home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol096
/
crck-51.a86
< prev
next >
Wrap
Text File
|
1984-04-29
|
17KB
|
827 lines
; 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