home *** CD-ROM | disk | FTP | other *** search
- ;
- ;XMODEM.ASM V3.2, BY KEITH PETERSEN, W8SDZ
- ; (revised 9/13/80)
- ;
- ;CP/M - CP/M FILE TRANSFER PROGRAM
- ;BASED ON MODEM.ASM V2.0, BY WARD CHRISTENSEN
- ;THIS PROGRAM IS INTENDED FOR USE ON REMOTE CP/M
- ;SYSTEMS WHERE IT IS IMPORTANT THAT THE INITIALIZATION
- ;OF THE MODEM NOT BE CHANGED, SUCH AS WHEN USING
- ;THE PMMIBYE PROGRAM. THE BAUD RATE AND NUMBER OF BITS
- ;REMAINS THE SAME AS WHATEVER WAS SET PREVIOUSLY.
- ;THERE IS NO DISCONNECT, TERMINAL OR ECHO OPTION.
- ;
- ;NOTE: THIS FILE WILL ASSEMBLE, WITHOUT NEED FOR
- ;EDITING, TO WORK WITH A PMMI MM-103 MODEM. SEE
- ;EQUATES FOR OTHER OPTIONS INCLUDING SYSTEM CLOCK
- ;FREQUENCY AND OTHER TYPES OF MODEMS.
- ;
- ; Added conditional assembly to prevent filetypes
- ;'.COM' or '.??#' from being sent to distant end
- ;and added conditional assembly of test for '.COM'
- ;filetype on receive as well. See 'NOCOM' below.
- ; Any filetype ending in '#' will not be sent by
- ;this program if 'NOCOM' is set to TRUE.
- ; 9-SEP-80 J.SEYMOUR
- ;
- FALSE EQU 0
- TRUE EQU NOT FALSE
- ;
- STDCPM EQU TRUE ;TRUE, IS STANDARD CP/M
- ALTCPM EQU FALSE ;TRUE, IS H8 OR TRS-80 CP/M
- ;
- IF STDCPM
- BASE EQU 0 ;CP/M BASE ADDRESS
- ENDIF
- ;
- IF ALTCPM
- BASE EQU 4200H ;ALTERNATE CP/M BASE ADDRESS
- ENDIF
- ;
- PMMI EQU TRUE ;TRUE, IS PMMI
- ;
- DCH EQU FALSE ;TRUE, IS D.C. HAYES
- ;
- NOCOM EQU TRUE ;TRUE, NO .COM OR .??# FILES
- ;SENT OR '.COM' RECEIVED
- ;
- IF PMMI
- MODCTLP EQU 0C0H ;PMMI VALUES
- MODSNDB EQU 1 ;BIT TO TEST FOR SEND
- MODSNDR EQU 1 ;VALUE WHEN READY
- MODRCVB EQU 2 ;BIT TO TEST FOR RECEIVE
- MODRCVR EQU 2 ;VALUE WHEN READY
- MODDATP EQU 0C1H ;DATA PORT
- BAUDRP EQU 0C2H ;BAUD RATE OUTPUT
- MODCTL2 EQU 0C3H ;SECOND CTL PORT
- ENDIF
- ;
- IF DCH
- MODCTLP EQU 82H ;D. C. HAYES VALUES
- MODSNDB EQU 2 ;BIT TO TEST FOR SEND
- MODSNDR EQU 2 ;VALUE WHEN READY
- MODRCVB EQU 1 ;BIT TO TEST FOR RECEIVE
- MODRCVR EQU 1 ;VALUE WHEN READY
- MODDATP EQU 80H ;DATA PORT
- MODCTL2 EQU 81H ;SECOND CTL PORT
- ENDIF
- ;
- ;IF YOU ARE USING AN EXTERNAL MODEM (NOT S-100 PLUG-IN)
- ;CHANGE THESE EQUATES FOR YOUR MODEM PORT REQUIREMENTS
- ;
- IF NOT PMMI AND NOT DCH
- MODCTLP EQU 02H ;PUT YOUR MODEM CONTROL PORT HERE
- MODSNDB EQU 80H ;YOUR BIT TO TEST FOR SEND
- MODSNDR EQU 80H ;YOUR VALUE WHEN READY
- MODRCVB EQU 40H ;YOUR BIT TO TEST FOR RECEIVE
- MODRCVR EQU 40H ;YOUR VALUE WHEN READY
- MODDATP EQU 03H ;YOUR MODEM DATA PORT
- ENDIF ;END OF EXTERNAL MODEM EQUATES
- ;
- ERRLIM EQU 10 ;MAX ALLOWABLE ERRORS
- ;
- FASTCLK EQU FALSE ;PUT TRUE HERE FOR 4 MHZ CLOCK
- ;
- ;DEFINE ASCII CHARACTERS USED
- ;
- SOH EQU 1 ;START OF HEADER
- EOT EQU 4 ;END OF TRANSMISSION
- ACK EQU 6 ;ACKNOWLEDGE
- NAK EQU 15H ;NEG ACKNOWLEDGE
- CAN EQU 18H ;CONTROL-X FOR CANCEL
- LF EQU 10 ;LINEFEED
- CR EQU 13 ;CARRIAGE RETURN
- ;
- ORG BASE+100H
- ;
- ;INIT PRIVATE STACK
- LXI H,0 ;HL=0
- DAD SP ;HL=STACK FROM CP/M
- SHLD STACK ;..SAVE IT
- LXI SP,STACK ;SP=MY STACK
- CALL ILPRT ;PRINT:
- DB CR,LF
- DB 'XMODEM ver 3.2',CR,LF,0
- ;
- ;GET OPTION
- ;
- LDA FCB+1 ;GET OPTION (S or R)
- PUSH PSW ;SAVE OPTION
- ;
- ;MOVE THE FILENAME FROM FCB 2 TO FCB 1
- ;
- CALL MOVEFCB
- ;
- ;GOBBLE UP GARBAGE CHARS FROM THE LINE
- ;PRIOR TO RECEIVE OR SEND
- ;
- IN MODDATP
- IN MODDATP
- ;
- ;JMP TO APPROPRIATE FUNCTION
- ;
- POP PSW ;GET OPTION
- ;
- CPI 'S' ;SEND..
- JZ SENDFIL ;..A FILE?
- ;
- CPI 'R' ;RECEIVE..
- JZ RCVFIL ;..A FILE?
- ;
- ;INVALID OPTION
- CALL ERXIT ;EXIT W/ERROR
- DB '++INVALID OPTION ON XMODEM '
- DB 'COMMAND++',CR,LF
- DB 'Must be S for SEND or R for '
- DB 'RECEIVE',CR,LF,'$'
- ;
- * * * * * * * * * * * * * * * * * * * * *
- * *
- * SENDFIL: SENDS A CP/M FILE *
- * *
- * * * * * * * * * * * * * * * * * * * * *
- ;
- ;THE CP/M FILE SPECIFIED IN THE MODEM COMMAND
- ;IS TRANSFERRED OVER THE PHONE TO ANOTHER
- ;COMPUTER RUNNING MODEM WITH THE "R" (RECEIVE)
- ;OPTION. THE DATA IS SENT ONE SECTOR AT A
- ;TIME WITH HEADERS AND CHECKSUMS, AND RE-
- ;TRANSMISSION ON ERRORS.
- ;
- ;
- SENDFIL CALL OPENFIL ;OPEN THE FILE
- MVI E,80 ;WAIT 80 SEC..
- CALL WAITNAK ;..FOR INITIAL NAK
- SENDLP CALL RDSECT ;READ A SECTOR
- JC SENDEOF ;SEND EOF IF DONE
- CALL INCRSNO ;BUMP SECTOR #
- XRA A ;ZERO ERROR..
- STA ERRCT ;..COUNT
- SENDRPT CALL SENDHDR ;SEND A HEADER
- CALL SENDSEC ;SEND DATA SECTOR
- CALL SENDCKS ;SEND CKSUM
- CALL GETACK ;GET THE ACK
- JC SENDRPT ;REPEAT IF NO ACK
- JMP SENDLP ;LOOP UNTIL EOF
- ;
- ;FILE SENT, SEND EOT'S
- ;
- SENDEOF MVI A,EOT ;SEND..
- CALL SEND ;..AN EOT
- CALL GETACK ;GET THE ACK
- JC SENDEOF ;LOOP IF NO ACK
- JMP EXIT ;ALL DONE
- ;
- * * * * * * * * * * * * * * * * * * * * *
- * *
- * RCVFIL: RECEIVE A FILE *
- * *
- * * * * * * * * * * * * * * * * * * * * *
- ;
- ;RECEIVES A FILE IN BLOCK FORMAT AS SENT
- ;BY ANOTHER PERSON DOING "MODEM S FN.FT".
- ;
- RCVFIL EQU $
- ;
- IF NOCOM
- LXI H,FCB+9 ;POINT TO FILETYPE
- MVI A,'C' ;1ST LETTER
- CMP M ;IS IT C ?
- JNZ CONTINU ;IF NOT, CONTINUE NORMALLY
- INX H ;GET 2ND LETTER
- MVI A,'O' ;2ND LETTER
- CMP M ;IS IT O ?
- JNZ CONTINU ;IF NOT, CONTINUE NORMALLY
- INX H ;GET 3RD LETTER
- MVI A,'M' ;3RD LETTER
- CMP M ;IS IT M ?
- JNZ CONTINU ;IF NOT, CONTINUE NORMALLY
- CALL ERXIT ;EXIT, PRINT ERROR MESSAGE
- DB '++CAN''T RECEIVE A .COM FILE++'
- DB CR,LF,CR,LF
- DB 'Rename filetype ".OBJ" and try again'
- DB CR,LF,'$'
- ENDIF
- ;
- CONTINU CALL CHEKFIL ;SEE IF FILE EXISTS
- CALL MAKEFIL ;..THEN MAKE NEW
- CALL ILPRT ;PRINT:
- DB 'FILE OPEN, READY TO RECEIVE',CR,LF,0
- ;
- RCVLP CALL RCVSECT ;GET A SECTOR
- JC RCVEOT ;GOT EOT
- CALL WRSECT ;WRITE THE SECTOR
- CALL INCRSNO ;BUMP SECTOR #
- CALL SENDACK ;ACK THE SECTOR
- JMP RCVLP ;LOOP UNTIL EOF
- ;
- ;GOT EOT ON SECTOR - FLUSH BUFFERS, END
- ;
- RCVEOT CALL WRBLOCK ;WRITE THE LAST BLOCK
- CALL SENDACK ;ACK THE SECTOR
- CALL CLOSFIL ;CLOSE THE FILE
- JMP EXIT ;ALL DONE
- ;
- * * * * * * * * * * * * * * * * * * * * *
- * *
- * SUBROUTINES *
- * *
- * * * * * * * * * * * * * * * * * * * * *
- ;
- ;
- ;----> RCVSECT: RECEIVE A SECTOR
- ;
- ;RETURNS WITH CARRY SET IF EOT RECEIVED.
- ;
- RCVSECT XRA A ;GET 0
- STA ERRCT ;INIT ERROR COUNT
- ;
- RCVRPT MVI B,10 ;10 SEC TIMEOUT
- CALL RECV ;GET SOH/EOT
- JC RCVSTOT ;TIMEOUT
- CPI SOH ;GET SOH?
- JZ RCVSOH ;..YES
- ;
- ;EARLIER VERS. OF MODEM PROG SENT SOME NULLS -
- ;IGNORE THEM
- ;
- ORA A ;00 FROM SPEED CHECK?
- JZ RCVRPT ;YES, IGNORE IT
- CPI EOT ;END OF TRANSFER?
- STC ;RETURN WITH CARRY..
- RZ ;..SET IF EOT
- ;
- ;DIDN'T GET SOH OR EOT -
- ;
- ;DIDN'T GET VALID HEADER - PURGE THE LINE,
- ;THEN SEND NAK.
- ;
- RCVSERR MVI B,1 ;WAIT FOR 1 SEC..
- CALL RECV ;..WITH NO CHARS
- JNC RCVSERR ;LOOP UNTIL SENDER DONE
- MVI A,NAK ;SEND..
- CALL SEND ;..THE NAK
- LDA ERRCT ;ABORT IF..
- INR A ;..WE HAVE REACHED..
- STA ERRCT ;..THE ERROR..
- CPI ERRLIM ;..LIMIT?
- JC RCVRPT ;..NO, TRY AGAIN
- ;
- ;10 ERRORS IN A ROW -
- ;
- RCVSABT CALL CLOSFIL ;KEEP WHATEVER WE GOT
- CALL ERXIT
- DB '++UNABLE TO RECEIVE BLOCK '
- DB '- ABORTING++',CR,LF,'$'
- ;
- ;TIMEDOUT ON RECEIVE
- ;
- RCVSTOT JMP RCVSERR ;BUMP ERR CT, ETC.
- ;
- ;GOT SOH - GET BLOCK #, BLOCK # COMPLEMENTED
- ;
- RCVSOH MVI B,1 ;TIMEOUT = 1 SEC
- CALL RECV ;GET SECTOR
- JC RCVSTOT ;GOT TIMEOUT
- MOV D,A ;D=BLK #
- MVI B,1 ;TIMEOUT = 1 SEC
- CALL RECV ;GET CMA'D SECT #
- JC RCVSTOT ;TIMEOUT
- CMA ;CALC COMPLEMENT
- CMP D ;GOOD SECTOR #?
- JZ RCVDATA ;YES, GET DATA
- ;
- ;GOT BAD SECTOR #
- ;
- JMP RCVSERR ;BUMP ERROR CT.
- ;
- RCVDATA MOV A,D ;GET SECTOR #
- STA RCVSNO ;SAVE IT
- MVI C,0 ;INIT CKSUM
- LXI H,BASE+80H ;POINT TO BUFFER
- ;
- RCVCHR MVI B,1 ;1 SEC TIMEOUT
- CALL RECV ;GET CHAR
- JC RCVSTOT ;TIMEOUT
- MOV M,A ;STORE CHAR
- INR L ;DONE?
- JNZ RCVCHR ;NO, LOOP
- ;
- ;VERIFY CHECKSUM
- ;
- MOV D,C ;SAVE CHECKSUM
- MVI B,1 ;TIMEOUT LEN.
- CALL RECV ;GET CHECKSUM
- JC RCVSTOT ;TIMEOUT
- CMP D ;CHECKSUM OK?
- JNZ RCVSERR ;NO, ERROR
- ;
- ;GOT A SECTOR, IT'S A DUP IF = PREV,
- ; OR OK IF = 1 + PREV SECTOR
- ;
- LDA RCVSNO ;GET RECEIVED
- MOV B,A ;SAVE IT
- LDA SECTNO ;GET PREV
- CMP B ;PREV REPEATED?
- JZ RECVACK ;ACK TO CATCH UP
- INR A ;CALC NEXT SECTOR #
- CMP B ;MATCH?
- JNZ ABORT ;NO MATCH - STOP SENDER, EXIT
- RET ;CARRY OFF - NO ERRORS
- ;
- ;PREV SECT REPEATED, DUE TO THE LAST ACK
- ;BEING GARBAGED. ACK IT SO SENDER WILL CATCH UP
- ;
- RECVACK CALL SENDACK ;SEND THE ACK,
- JMP RCVSECT ;GET NEXT BLOCK
- ;
- ;SEND AN ACK FOR THE SECTOR
- ;
- SENDACK MVI A,ACK ;GET ACK
- CALL SEND ;..AND SEND IT
- RET
- ;
- ;----> SENDHDR: SEND THE SECTOR HEADER
- ;
- ;SEND: (SOH) (BLOCK #) (COMPLEMENTED BLOCK #)
- ;
- SENDHDR MVI A,SOH ;SEND..
- CALL SEND ;..SOH,
- LDA SECTNO ;THEN SEND..
- CALL SEND ;..SECTOR #
- LDA SECTNO ;THEN SECTOR #
- CMA ;..COMPLEMENTED..
- CALL SEND ;..SECTOR #
- RET ;FROM SENDHDR
- ;
- ;----> SENDSEC: SEND THE DATA SECTOR
- ;
- SENDSEC MVI C,0 ;INIT CKSUM
- LXI H,BASE+80H ;POINT TO BUFFER
- SENDC MOV A,M ;GET A CHAR
- CALL SEND ;SEND IT
- INR L ;POINT TO NEXT CHAR
- JNZ SENDC ;LOOP IF <100H
- RET ;FROM SENDSEC
- ;
- ;----> SENDCKS: SEND THE CHECKSUM
- ;
- SENDCKS MOV A,C ;SEND THE..
- CALL SEND ;..CHECKSUM
- RET ;FROM SENDCKS
- ;
- ;----> GETACK: GET THE ACK ON THE SECTOR
- ;
- ;RETURNS WITH CARRY CLEAR IF ACK RECEIVED.
- ;IF AN ACK IS NOT RECEIVED, THE ERROR COUNT
- ;IS INCREMENTED, AND IF LESS THAN "ERRLIM",
- ;CARRY IS SET AND CONTROL RETURNS. IF THE
- ;ERROR COUNT IS AT "ERRLIM", THE PROGRAM
- ;ABORTS.
- ;
- GETACK MVI B,10 ;WAIT 10 SECONDS MAX
- CALL RECVDG ;RECV W/GARBAGE COLLECT
- JC GETATOT ;TIMED OUT
- CPI ACK ;OK? (CARRY OFF IF =)
- RZ ;YES, RET FROM GETACK
- ;
- ;TIMEOUT OR ERROR ON ACK - BUMP ERROR COUNT
- ;
- ACKERR LDA ERRCT ;GET COUNT
- INR A ;BUMP IT
- STA ERRCT ;SAVE BACK
- CPI ERRLIM ;AT LIMIT?
- RC ;NOT AT LIMIT
- ;
- ;REACHED ERROR LIMIT
- ;
- CSABORT CALL ERXIT
- DB '++CAN''T SEND SECTOR '
- DB '- ABORTING++',CR,LF,'$'
- ;
- ;TIMEOUT GETTING ACK
- ;
- GETATOT JMP ACKERR ;NO MSG
- ;
- ABORT LXI SP,STACK
- ;
- ABORTL MVI B,1 ;1 SEC. W/O CHARS.
- CALL RECV
- JNC ABORTL ;LOOP UNTIL SENDER DONE
- MVI A,CAN ;CONTROL X
- CALL SEND ;STOP SENDING END
- ;
- ABORTW MVI B,1 ;1 SEC W/O CHARS.
- CALL RECV
- JNC ABORTW ;LOOP UNTIL SENDER DONE
- MVI A,' ' ;GET A SPACE...
- CALL SEND ;TO CLEAR OUT CONTROL X
- CALL ERXIT ;EXIT WITH ABORT MSG
- DB 'XMODEM PROGRAM CANCELLED',CR,LF,'$'
- ;
- ;----> INCRSNO: INCREMENT SECTOR #
- ;
- INCRSNO LDA SECTNO ;INCR..
- INR A ;..SECT..
- STA SECTNO ;..NUMBER
- RET
- ;
- ;----> CHEKFIL: SEE IF FILE EXISTS
- ;
- ;IF IT EXISTS, SAY IT MUST BE ERASED.
- ;
- CHEKFIL LXI D,FCB ;POINT TO CTL BLOCK
- MVI C,SRCHF ;SEE IF IT..
- CALL BDOS ;..EXISTS
- INR A ;FOUND?
- RZ ;..NO, RETURN
- CALL ERXIT ;EXIT, PRINT ERROR MESSAGE
- DB '++FILE EXISTS, USE A DIFFERENT NAME++'
- DB CR,LF,'$'
- ;
- ;----> MAKEFIL: MAKES THE FILE TO BE RECEIVED
- ;
- MAKEFIL LXI D,FCB ;POINT TO FCB
- MVI C,MAKE ;GET BDOS FNC
- CALL BDOS ;TO THE MAKE
- INR A ;FF=BAD?
- RNZ ;OPEN OK
- ;DIRECTORY FULL - CAN'T MAKE FILE
- CALL ERXIT
- DB '++ERROR - CAN''T MAKE FILE++',CR,LF
- DB 'Directory must be full',CR,LF,'$'
- ;
- ;----> OPENFIL: OPENS THE FILE TO BE SENT
- ;
- OPENFIL LXI D,FCB ;POINT TO FILE
- MVI C,OPEN ;GET FUNCTION
- CALL BDOS ;OPEN IT
- INR A ;OPEN OK?
- JNZ OPENOK ;..YES
- CALL ERXIT ;..NO, ABORT
- DB '++FILE NOT FOUND++',CR,LF,'$'
- ;
- ;CHECK FOR DISTRIBUTION-PROTECTED FILE
- ;
- OPENOK LDA FCB+1 ;FIRST CHAR OF FILE NAME
- ANI 80H ;CHECK BIT 7
- JZ OPENOK2 ;IT WAS OFF, FILE CAN BE SENT
- ;
- OPENOT CALL ERXIT ;EXIT W/MESSAGE
- DB '++THIS FILE IS NOT FOR DISTRIBUTION, SORRY++'
- DB CR,LF,'$'
- ;
- OPENOK2 EQU $
- ;
- IF NOCOM
- LXI H,FCB+11
- MOV A,M ;CHECK FOR PROTECT ATTR
- ANI 7FH ;REMOVE CP/M 2.x ATTRS
- CPI '#' ;CHK FOR '#' AS LAST FIRST
- JZ OPENOT ;IF '#', CAN'T SEND, SHOW WHY
- CPI 'M' ;IF NOT, CHK FOR '.COM'
- JNZ OPENOK3 ;IF NOT, OK TO SEND
- DCX H
- MOV A,M ;CHK NEXT CHAR
- ANI 7FH ;STRIP ATTRIBUTES
- CPI 'O' ; 'O'?
- JNZ OPENOK3 ;IF NOT, OK TO SEND
- DCX H
- MOV A,M ;NOW CHK FIRST CHAR
- ANI 7FH ;STRIP ATTRIBUTES
- CPI 'C' ; 'C' AS IN '.COM'?
- JNZ OPENOK3 ;IF NOT, CONTINUE
- CALL ERXIT ;EXIT W/MESSAGE
- DB '++CAN''T SEND A .COM FILE++'
- DB CR,LF,'$'
- ENDIF
- ;
- OPENOK3 CALL ILPRT ;PRINT:
- DB 'FILE OPEN, EXTENT LENGTH: ',0
- LDA FCB+15 ;GET # SECTORS
- CALL HEXO ;PRINT IN HEX
- CALL ILPRT ;PRINT H AFTER NUMBER, THEN CR,LF
- DB 'H',CR,LF,0
- RET
- ;
- ;----> CLOSFIL: CLOSES THE RECEIVED FILE
- ;
- CLOSFIL LXI D,FCB ;POINT TO FILE
- MVI C,CLOSE ;GET FUNCTION
- CALL BDOS ;CLOSE IT
- INR A ;CLOSE OK?
- RNZ ;..YES, RETURN
- CALL ERXIT ;..NO, ABORT
- DB '++CAN''T CLOSE FILE++',CR,LF,'$'
- ;
- ;----> RDSECT: READS A SECTOR
- ;
- ;FOR SPEED, THIS ROUTINE BUFFERS UP 16
- ;SECTORS AT A TIME.
- ;
- RDSECT LDA SECINBF ;GET # SECT IN BUFF.
- DCR A ;DECREMENT..
- STA SECINBF ;..IT
- JM RDBLOCK ;EXHAUSTED? NEED MORE.
- LHLD SECPTR ;GET POINTER
- LXI D,BASE+80H ;TO DATA
- CALL MOVE128 ;MOVE TO BUFFER
- SHLD SECPTR ;SAVE BUFFER POINTER
- RET ;FROM "READSEC"
- ;
- ;BUFFER IS EMPTY - READ IN ANOTHER BLOCK OF 16
- ;
- RDBLOCK LDA EOFLG ;GED EOF FLAG
- CPI 1 ;IS IT SET/
- STC ;TO SHOW EOF
- RZ ;GOT EOF
- MVI C,0 ;SECTORS IN BLOCK
- LXI D,DBUF ;TO DISK BUFFER
- RDSECLP PUSH B
- PUSH D
- MVI C,STDMA ;SET DMA..
- CALL BDOS ;..ADDR
- LXI D,FCB
- MVI C,READ
- CALL BDOS
- POP D
- POP B
- ORA A ;READ OK?
- JZ RDSECOK ;YES
- DCR A ;EOF?
- JZ REOF ;GOT EOF
- ;
- ;READ ERROR
- ;
- CALL ERXIT
- DB '++FILE READ ERROR',CR,LF,'$'
- ;
- RDSECOK LXI H,80H ;ADD LENGTH OF ONE SECTOR...
- DAD D ;...TO NEXT BUFF
- XCHG ;BUFF TO DE
- INR C ;MORE SECTORS?
- MOV A,C ;GET COUNT
- CPI 16 ;DONE?
- JZ RDBFULL ;..YES, BUFF IS FULL
- JMP RDSECLP ;READ MORE
- ;
- REOF MVI A,1
- STA EOFLG ;SET EOF FLAG
- MOV A,C
- ;
- ;BUFFER IS FULL, OR GOT EOF
- ;
- RDBFULL STA SECINBF ;STORE SECTOR COUNT
- LXI H,DBUF ;INIT BUFFER..
- SHLD SECPTR ;..POINTER
- LXI D,BASE+80H ;RESET..
- MVI C,STDMA ;..DMA..
- CALL BDOS ;..ADDR
- JMP RDSECT ;PASS SECT TO CALLER
- ;
- ;----> WRSECT: WRITE A SECTOR
- ;
- ;WRITES THE SECTOR INTO A BUFFER. WHEN 16
- ;HAVE BEEN WRITTEN, WRITES THE BLOCK TO DISK.
- ;
- ;ENTRY POINT "WRBLOCK" FLUSHES THE BUFFER AT EOF.
- ;
- WRSECT LHLD SECPTR ;GET BUFF ADDR
- XCHG ;TO DE FOR MOVE
- LXI H,BASE+80H ;FROM HERE
- CALL MOVE128 ;MOVE TO BUFFER
- XCHG ;SAVE NEXT..
- SHLD SECPTR ;..BLOCK POINTER
- LDA SECINBF ;BUMP THE..
- INR A ;..SECTOR #..
- STA SECINBF ;..IN DHE BUFF
- CPI 16 ;HAVE WE 16?
- RNZ ;NO, RETURN
- ;
- ;----> WRBLOCK: WRITES A BLOCK TO DISK
- ;
- WRBLOCK LDA SECINBF ;# SECT IN BUFFER
- ORA A ;0 MEANS END OF FILE
- RZ ;NONE TO WRITE
- MOV C,A ;SAVE COUNT
- LXI D,DBUF ;POINT TO DISK BUFF
- ;
- DKWRLP PUSH H
- PUSH D
- PUSH B
- MVI C,STDMA ;SET DMA
- CALL BDOS ;TO BUFFER
- LXI D,FCB ;THEN WRITE
- MVI C,WRITE ;..THE..
- CALL BDOS ;..BLOCK
- POP B
- POP D
- POP H
- ORA A
- JNZ WRERR ;OOPS, ERROR
- LXI H,80H ;LENGTH OF 1 SECT
- DAD D ;HL= NEXT BUFF
- XCHG ;TO DE FOR SETDMA
- DCR C ;MORE SECTORS?
- JNZ DKWRLP ;..YES, LOOP
- XRA A ;GET A ZERO
- STA SECINBF ;RESET # OF SECTORS
- LXI H,DBUF ;RESET BUFFER..
- SHLD SECPTR ;..POINTER
- ;
- RSDMA LXI D,BASE+80H ;RESET..
- MVI C,STDMA ;..DMA..
- CALL BDOS ;..ADDR
- RET
- ;
- WRERR CALL RSDMA ;RESET DMA TO NORM.
- MVI C,CAN ;CANCEL..
- CALL SEND ;..SENDER
- CALL ERXIT ;EXIT W/MSG:
- DB '++ERROR WRITING FILE++',CR,LF,'$'
- ;
- ;----> RECV: RECEIVE A CHARACTER
- ;
- ;TIMEOUT TIME IS IN B, IN SECONDS. ENTRY VIA
- ;"RECVDG" DELETES GARBAGE CHARACTERS ON THE
- ;LINE. FOR EXAMPLE, HAVING JUST SENT A SECTOR,
- ;CALLING RECVDG WILL DELETE ANY LINE-NOISE-INDUCED
- ;CHARACTERS "LONG" BEFORE THE ACK/NAK WOULD
- ;BE RECEIVED.
- ;
- RECVDG EQU $ ;RECEIVE W/GARBAGE DELETE
- IN MODDATP ;GET A CHAR
- IN MODDATP ;..TOTALLY PURGE UART
- ;
- RECV PUSH D ;SAVE
- ;
- IF FASTCLK ;4MHZ?
- MOV A,B ;GET TIME REQUEST
- ADD A ;DOUBLE IT
- MOV B,A ;NEW TIME IN B
- ENDIF
- ;
- MSEC LXI D,50000 ;1 SEC DCR COUNT
- ;
- IF NOT DCH
- MWTI IN MODCTLP ;CHECK STATUS
- ENDIF
- ;
- IF DCH
- MWTI IN MODCTL2 ;CHECK STATUS
- ENDIF
- ;
- ANI MODRCVB ;ISOLATE BIT
- CPI MODRCVR ;READY?
- JZ MCHAR ;GOT CHAR
- DCR E ;COUNT..
- JNZ MWTI ;..DOWN..
- DCR D ;..FOR..
- JNZ MWTI ;..TIMEOUT
- DCR B ;MORE SECONDS?
- JNZ MSEC ;YES, WAIT
- ;
- ;MODEM TIMED OUT RECEIVING
- ;
- POP D ;RESTORE D,E
- STC ;CARRY SHOWS TIMEOUT
- RET
- ;
- ;GOT CHAR FROM MODEM
- ;
- MCHAR IN MODDATP ;READ THE CHAR
- POP D ;RESTORE DE
- ;
- ;CALC CHECKSUM
- ;
- PUSH PSW ;SAVE THE CHAR
- ADD C ;ADD TO CHECKSUM
- MOV C,A ;SAVE CHECKSUM
- POP PSW ;RESTORE CHAR
- ORA A ;CARRY OFF: NO ERROR
- RET ;FROM "RECV"
- ;
- ;----> SEND: SEND A CHARACTER TO THE MODEM
- ;
- SEND PUSH PSW ;SAVE THE CHAR
- ADD C ;CALC CKSUM
- MOV C,A ;SAVE CKSUM
- ;
- IF NOT DCH
- SENDW IN MODCTLP ;GET STATUS
- ENDIF
- ;
- IF DCH
- SENDW IN MODCTL2 ;GET STATUS
- ENDIF
- ;
- ANI MODSNDB ;ISOLATE READY BIT
- CPI MODSNDR ;READY?
- JNZ SENDW ;..NO, WAIT
- POP PSW ;GET CHAR
- OUT MODDATP ;OUTPUT IT
- RET ;FROM "SEND"
- ;
- ;----> WAITNAK: WAITS FOR INITIAL NAK
- ;
- ;TO ENSURE NO DATA IS SENT UNTIL THE RECEIVING
- ;PROGRAM IS READY, THIS ROUTINE WAITS FOR THE
- ;THE FIRST TIMEOUT-NAK FROM THE RECEIVER.
- ;(E) CONTAINS THE # OF SECONDS TO WAIT.
- ;
- WAITNAK MVI B,1 ;TIMEOUT DELAY
- CALL RECV ;DID WE GET..
- CPI NAK ;..A NAK?
- RZ ;YES, SEND BLOCK
- DCR E ;80 TRIES?
- JZ ABORT ;YES, ABORT
- JMP WAITNAK ;NO, LOOP
- ;
- ;----> MOVEFCB: MOVES FCB(2) TO FCB
- ;
- ;I ATTEMPTED TO MAKE THE MODEM COMMAND 'NATURAL',
- ;I.E. MODEM SEND FILENAME (MODEM S FN.FT) RATHER
- ;THAN MODEM FILENAME SEND (MODEM FN.FT S) SO THIS
- ;ROUTINE MOVES THE FILENAME FROM THE SECOND FCB
- ;TO THE FIRST
- ;
- MOVEFCB LXI H,FCB+16 ;FROM
- LXI D,FCB ;TO
- MVI B,16 ;LEN
- CALL MOVE ;DO THE MOVE
- XRA A ;GET 0
- STA FCBSNO ;ZERO SECTOR #
- STA FCBEXT ;..AND EXTENT
- RET
- ;
- CTYPE PUSH B ;SAVE..
- PUSH D ;..ALL..
- PUSH H ;..REGS
- MOV E,A ;CHAR TO E
- MVI C,WRCON ;GET BDOS FNC
- CALL BDOS ;PRIN THE CHR
- POP H ;RESTORE..
- POP D ;..ALL..
- POP B ;..REGS
- RET ;FROM "CTYPE"
- ;
- HEXO PUSH PSW ;SAVE FOR RIGHT DIGIT
- RAR ;RIGHT..
- RAR ;..JUSTIFY..
- RAR ;..LEFT..
- RAR ;..DIGIT..
- CALL NIBBL ;PRINT LEFT DIGIT
- POP PSW ;RESTORE RIGHT
- ;
- NIBBL ANI 0FH ;ISOLATE DIGIT
- CPI 10 ;IS IS <10?
- JC ISNUM ;YES, NOT ALPHA
- ADI 7 ;ADD ALPHA BIAS
- ;
- ISNUM ADI '0' ;MAKE PRINTABLE
- JMP CTYPE ;..THEN TYPE IT
- ;
- ;----> ILPRT: INLINE PRINT OF MSG
- ;
- ;THE CALL TO ILPRT IS FOLLOWED BY A MESSAGE,
- ;BINARY 0 AS THE END.
- ;
- ILPRT XTHL ;SAVE HL, GET HL=MSG
- ;
- ILPLP MOV A,M ;GET CHAR
- ORA A ;END OF MSG?
- JZ ILPRET ;..YES, RETURN
- CALL CTYPE ;TYPE THE MSG
- INX H ;TO NEXT CHAR
- JMP ILPLP ;LOOP
- ;
- ILPRET XTHL ;RESTORE HL
- RET ;PAST MSG
- ;
- ;----> ERXIT: EXIT PRINTING MSG FOLLOWING CALL
- ;
- ERXIT POP D ;GET MESSAGE
- MVI C,PRINT ;GET BDOS FNC
- CALL BDOS ;PRINT MESSAGE
- ;
- EXIT LHLD STACK ;GET ORIGINAL STACK
- SPHL ;RESTORE IT
- RET ;--EXIT-- TO CP/M
- ;
- ;MOVE 128 CHARACTERS
- ;
- MOVE128 MVI B,128 ;SET MOVE COUNT
- ;
- ;MOVE FROM (HL) TO (DE) LENGTH IN (B)
- ;
- MOVE MOV A,M ;GET A CHAR
- STAX D ;STORE IT
- INX H ;TO NEXT "FROM"
- INX D ;TO NEXT "TO"
- DCR B ;MORE?
- JNZ MOVE ;..YES, LOOP
- RET ;..NO, RETURN
- ;
- ;TEMPORARY STORAGE AREA
- ;
- RCVSNO DB 0 ;SECT # RECEIVED
- SECTNO DB 0 ;CURRENT SECTOR NUMBER
- ERRCT DB 0 ;ERROR COUNT
- ;FOLLOWING 3 USED BY DISK BUFFERING ROUTINES
- EOFLG DB 0 ;EOF FLAG (1=TRUE)
- SECPTR DW DBUF
- SECINBF DB 0 ;# OF SECTORS IN BUFFER
- DS 60 ;STACK AREA
- STACK DS 2 ;STACK POINTER
- ;
- ;16 SECTOR DISK BUFFER
- ;
- DBUF EQU $ ;16 SECTOR DISK BUFFER
- ;
- ; BDOS EQUATES (VERSION 2)
- ;
- RDCON EQU 1
- WRCON EQU 2
- PRINT EQU 9
- CONST EQU 11 ;CONSOLE STAT
- OPEN EQU 15 ;0FFH=NOT FOUND
- CLOSE EQU 16 ; " "
- SRCHF EQU 17 ; " "
- SRCHN EQU 18 ; " "
- ERASE EQU 19 ;NO RET CODE
- READ EQU 20 ;0=OK, 1=EOF
- WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC
- MAKE EQU 22 ;0FFH=BAD
- REN EQU 23 ;0FFH=BAD
- STDMA EQU 26 ;SET DMA
- BDOS EQU BASE+5
- FCB EQU BASE+5CH ;SYSTEM FCB
- FCBEXT EQU FCB+12 ;FILE EXTENT
- FCBSNO EQU FCB+32 ;SECTOR #
- FCB2 EQU BASE+6CH ;SECOND FCB
- ;
- END
-
-