home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG019.ARK
/
LINK.ASM
< prev
next >
Wrap
Assembly Source File
|
1985-02-10
|
21KB
|
649 lines
; LINK - SUPPORT COMMUNICATIONS LINK WITH CYBER
;
; L.E. HUGHES EDCAM JULY, 1977
;
; *LINK* IS A CP/M TRANSIENT COMMAND WHICH ALLOWS THE USER TO
; ESTABLISH A COMMUNICATIONS LINK WITH A REMOTE COMPUTER
; *LINK* CURRENTLY SUPPORTS TWO WAY TRANSFER OF TEXT FILES BETWEEN
; THE CP/M DISK AND THE REMOTE COMPUTER. THE FOLLOWING CONTROL
; CODES MAY BE INITIATED FROM THE CONSOLE KEYBOARD:
;
; CTRL-S SEND TEXT FILE FROM DISK TO CYBER
; CTRL-R ENABLE TEXT-FILE-LOADER (INTO MEMORY)
; CTRL-Q DISABLE TEXT FILE LOADER, WRITE MEMORY TO DISK
; BDOS ENTRY POINT AND FUNCTION CODES
BDOS EQU 0005H
OFFC EQU 15 ;OPEN FILE
CFFC EQU 16 ;CLOSE FILE
DFFC EQU 19 ;DELETE FILE
RRFC EQU 20 ;READ RECORD
WRFC EQU 21 ;WRITE RECORD
MFFC EQU 22 ;MAKE FILE
; DEFAULT FCB AND FIELD DEFINITIONS
FCB EQU 5CH
FN EQU 1 ;FILE NAME FIELD (REL)
FT EQU 9 ;FILE TYPE FIELD (REL)
NR EQU 32 ;NEXT RECORD FIELD (REL)
DBUF EQU 80H ;DEFAULT DISK BUFFER ADDRESS
; ASCII CONTROL CHARACTERS
BEL EQU 007Q ;BELL
LF EQU 012Q ;LINE FEED
CR EQU 015Q ;CARRIAGE RETURN
DEL EQU 177Q ;DELETE
; I/O PORT ADDRESSES
COND EQU 001Q ;CONSOLE DATA PORT
CONS EQU 000Q ;CONSOLE STATUS PORT
MODD EQU 200Q ;MODEM DATA PORT
MODS EQU 201Q ;MODEM STATUS PORT
MODC EQU 202Q ;MODEM CONTROL PORT
; I/O SYMBOL DEFINITIONS
CTBE EQU 200Q ;CONSOLE TRANSMIT BUFFER EMPTY
CRDA EQU 100Q ;CONSOLE READ DATA AVAILABLE
MTBE EQU 002Q ;MODEM TRANSMIT BUFFER EMPTY
MRDA EQU 001Q ;MODEM READ DATA AVAILABLE
O300 EQU 005Q ;ORIGINATE MODE / 300 BAUD
HOOK EQU 200Q ;OFF-HOOK (RAISED)
TXE EQU 002Q ;TRANSMIT ENABLE
WORD EQU 026Q ;8 BITS, NO PARITY, 1 STOP BIT
; MAIN PROGRAM
ORG 100H
LINK: LXI H,0 ;SAVE OLD STACK POINTER
DAD SP
SHLD OLDSP
LXI SP,STACK+64 ;CREATE LOCAL STACK
IN MODS ;JUMP IF CARRIER DETECT ALREADY ON
ANI 40H
JNZ LINK2
LXI H,80H ;GET PHONE NUMBER FROM COMMAND LINE
MOV B,M
INX H
LXI D,NUM
INR B
GPN1: DCR B
JZ GPN2
MOV A,M
INX H
CPI ' '
JZ GPN1
STAX D
INX D
JMP GPN1
GPN2: MVI A,0
STAX D
MVI B,0FFH ;CLEAR MODEM CONTROL REGISTER
CALL MCOFF
MVI B,O300 ;SET MODE TO ORIGINATE / 300 BAUD
CALL MCON
MVI A,WORD ;DEFINE UART WORD FORMAT
OUT MODS
MVI B,HOOK ;RAISE HOOK
CALL MCON
MVI B,40 ;PAUSE 2 SECONDS
DIAL0: CALL DELAY
DCR B
JNZ DIAL0
LXI H,NUM ;POINT TO PHONE NUMBER
DIAL1: MOV A,M ;FETCH NEXT DIGIT OF PHONE NUMBER
INX H
ORA A ;EXIT WHEN DONE
JZ DIAL2
CALL WCC
CPI '-' ;IGNORE DASHES IN NUMBER
JZ DIAL1
SUI '0' ;SUBTRACT ASCII BIAS
JNZ $+5 ;JUMP IF DIGIT NOT '0'
MVI A,10 ;SPECIAL CASE FOR 10 CLICKS
CALL PULSE ;DO THE CLICKS
JMP DIAL1 ;LOOP THRU ENTIRE PHONE NUMBER
DIAL2: LXI D,400 ;SETUP FOR 20 SECONDS MAX DELAY
CALL DELAY ;ALLOW CARRIER TO SETTLE
DIAL3: IN MODS ;JUMP IF CARRIER DETECT HIGH
ANI 40H
JNZ DIAL4
CALL DELAY ;WAIT ANOTHER 50 MS
DCX D
MOV A,D
ORA E
JNZ DIAL3
JMP LINKX ;EXIT IF NO RESPONSE
DIAL4: MVI B,TXE ;ENABLE TRANSMITTER
CALL MCON
MVI A,CR
CALL WCC
MVI A,LF
CALL WCC
LINK2: XRA A ;CLEAR CHAR BUFFERS
STA INCH
STA OUTCH
STA FLAG ;CLEAR TEXT SAVE FLAG
LXI H,TBUF ;SET PTR TO TBUF
SHLD PTR
LXI H,0 ;SIZE = 0
SHLD SIZE
CALL WCCR ;WRITE CR/LF TO CONSOLE
MVI A,BEL ;RING BELL ON CONSOLE, TO LET
CALL WCC ; CLONE KNOW WE'RE READY
; MAIN LOOP
LINK3: IN MODS ;EXIT IF CARRIER DETECT GOES BYE BYE
ANI 40H
JZ LINKX
IN CONS ;JUMP IF NO DATA FROM CONSOLE
ANI CRDA
JZ LINK4
IN COND ;ELSE READ CONSOLE DATA
ANI 177Q ;CALL PCC IF CONTROL CHAR
CPI 40Q
CC PCC
JC LINK4 ;JUMP IF PCC HANDLED CHAR
ORI 200Q ;ELSE SET VALID DATA BIT
STA INCH ;AND STORE IN INPUT CHAR BUFFER
LINK4: IN CONS ;JUMP IF CONSOLE XMIT BUFFER BUSY
ANI CTBE
JZ LINK5
LDA OUTCH ;JUMP IF NO DATA FOR CONSOLE
ORA A
JP LINK5
ANI 177Q ;ELSE DISCARD VALID DATA BIT
OUT COND ; AND OUTPUT CHAR TO CONSOLE
XRA A ; THEN CLEAR OUTPUT CHAR BUFFER
STA OUTCH
LINK5: IN MODS ;JUMP IF NO DATA FROM MODEM
ANI MRDA
JZ LINK6
IN MODD ;ELSE READ MODEM DATA
ANI 177Q ;DISCARD PARITY BIT
CALL SAVE ;SAVE CHAR IN TEXT BUFFER IF FLAG ON
ORI 200Q ;SET DATA VALID BIT
STA OUTCH ;STORE IN OUTPUT CHAR BUFFER
LINK6: IN MODS ;JUMP IF MODEM XMIT BUFFER BUSY
ANI MTBE
JZ LINK7
LDA INCH ;JUMP IF NO DATA FOR MODEM
ORA A
JP LINK7
ANI 177Q ;ELSE DISCARD VALID DATA BIT
OUT MODD ; AND OUTPUT CHAR TO MODEM
XRA A ; THEN CLEAR INPUT CHAR BUFFER
STA INCH
LINK7: JMP LINK3 ;END OF MAIN LOOP
LINKX: MVI B,0FFH ;CLEAR MODEM
CALL MCOFF
LHLD OLDSP
SPHL
RET
; DELAY - DELAY FOR 50 MILLISECONDS
DELAY: PUSH PSW
PUSH H
LXI H,4164
DEL1: DCX H
MOV A,H
ORA L
JNZ DEL1
POP H
POP PSW
RET
; PULSE - SEND A PULSES BY TAPPING HOOK
PULSE: PUSH PSW
MVI B,HOOK ;LOWER HOOK
CALL MCOFF
CALL DELAY ;PAUSE 50 MS
MVI B,HOOK ;RAISE HOOK
CALL MCON
CALL DELAY ;PAUSE 50 MS
POP PSW
DCR A ;DO IT A TIMES
JNZ PULSE
MVI A,10 ;PAUSE 500 MS
PUL1: CALL DELAY
DCR A
JNZ PUL1
RET
; MCON - TURN ON BIT(S) ON MODEM CONTROL PORT
MCON: PUSH PSW
LDA MCB
ORA B
STA MCB
OUT MODC
POP PSW
RET
; MCOFF - TURN OFF BIT(S) ON MODEM CONTROL PORT
MCOFF: PUSH PSW
MOV A,B
CMA
MOV B,A
LDA MCB
ANA B
STA MCB
OUT MODC
POP PSW
RET
; PCC - PROCESS CONTROL CHARACTER
PCC: CPI 'X'-100Q ;JUMP IF NOT CONTROL-X
JNZ PCC1
LHLD OLDSP ;ELSE CLEAN UP ACT AND GO HOME
SPHL
RET
PCC1: CPI 'S'-100Q ;JUMP IF NOT CONTROL-S
JNZ PCC2
CALL STF ;SEND TEXT FILE TO MODEM
STC ;TELL LINK TO IGNORE THIS CHARACTER
RET
PCC2: CPI 'R'-100Q ;JUMP IF NOT CONTROL-R
JNZ PCC3
MVI A,1 ;TURN ON TEXT SAVE FLAG
STA FLAG
STC
RET
PCC3: CPI 'Q'-100Q ;JUMP IF NOT CONTROL-Q
JNZ PCC4
XRA A ;TURN OFF TEXT SAVE FLAG
STA FLAG
CALL WTB ;WRITE TEXT BUFFER TO DISK
LXI H,TBUF ;CLEAR TEXT BUFFER
SHLD PTR
LXI H,0
SHLD SIZE
STC
RET
PCC4: STC ;LET LINK HANDLE ALL OTHER CONTROL CODES
CMC
RET
; STF - SEND TEXT FILE (TO MODEM)
STF: CALL GFN ;GET NAME OF DISK FILE TO SEND
JC STF6 ;JUMP IF FILE NAME ERROR
CALL OPEN ;TRY TO OPEN SPECIFIED FILE
CPI 255 ;JUMP IF FILE NOT FOUND
JZ STF7
XRA A ;ELSE REWIND FILE AND GET ON WITH IT
STA FCB+NR
STF1: CALL READ ;READ NEXT RECORD INTO DBUF
CPI 1 ;JUMP IF END-OF-FILE
JZ STF5
LXI H,DBUF ;POINT TO DISK BUFFER
MVI C,128
STF2: MOV A,M ;FETCH NEXT CHAR FROM DBUF
INX H
CPI 'Z'-100Q ;JUMP IF END-OF-FILE CHARACTER
JZ STF5
CPI LF ;IGNORE LINE FEEDS
JZ STF4
CALL WMC ;WRITE CHARACTER TO MODEM
CALL WCC ;WRITE CHARACTER TO CONSOLE
CPI CR ;JUMP IF NOT CARRIAGE RETURN
JNZ STF4
STF3: CALL RMC ;AWAIT LINE FEED FROM MODEM
CPI LF
JNZ STF3
CALL WCC ;ECHO LINE FEED TO CONSOLE
IN CONS
ANI CRDA
JZ STF4
IN COND
JMP STF5
STF4: DCR C ;LOOP THRU REST OF DBUF
JNZ STF2
JMP STF1 ;GO GET NEXT RECORD FROM DISK
STF5: CALL CLOSE ;CLEAN UP ACT AND GO HOME
MVI A,BEL ;RING BELL TO LET CLONE
CALL WCC ; KNOW WE'RE THROUGH
RET
STF6: LXI H,STFS1 ;PRINT 'FILE NAME ERROR'
CALL WCS
RET
STF7: LXI H,STFS2 ;PRINT 'FILE NOT FOUND'
CALL WCS
RET
STFS1: DB 'FILE NAME ERROR',CR,LF,0
STFS2: DB 'FILE NOT FOUND',CR,LF,0
; SAVE - SAVE CHAR IN TEXT BUFFER IF FLAG ON
;
; ENTRY CONDITIONS
; A - CHARACTER TO SAVE
SAVE: PUSH PSW
LDA FLAG
ORA A
JNZ SAVE1
POP PSW
RET
SAVE1: POP PSW
PUSH H
LHLD PTR
ANI 7FH ;DISCARD PARITY BIT
JZ SAVE2 ;JUMP IF CHAR IS A NULL
MOV M,A
INX H
SAVE2: CMA ;DISPLAY CHAR ON LIGHTS
OUT 0FFH
CMA
SHLD PTR
LHLD SIZE ;SIZE = SIZE + 1
INX H
SHLD SIZE
POP H
RET
; WTB - WRITE TEXT BUFFER TO DISK
WTB: LHLD SIZE ;JUMP IF TEXT BUFFER EMPTY
MOV A,L
ORA H
JZ WTB5
CALL GFN ;GET FILE NAME
JC WTB6 ;JUMP IF FILE NAME ERROR
CALL DELT ;DELETE OLD FILE, IF ANY
CALL MAKE ;MAKE NEW FILE
XRA A ;REWIND FILE
STA FCB+NR
LHLD SIZE ;DE = TBUF SIZE
XCHG
LXI H,DBUF ;TOP OF STACK POINTS TO DBUF
PUSH H
LXI H,TBUF ;HL POINTS TO TBUF
WTB1: MVI C,128 ;DISK BUFFER SIZE
WTB2: MOV A,M ;FETCH NEXT BYTE OF TBUF
INX H
XTHL
MOV M,A ;STORE IN DBUF
INX H
XTHL
DCX D ;SIZE = SIZE - 1
MOV A,D ;EXIT LOOP IF SIZE = 0
ORA E
JZ WTB3
DCR C ;LOOP UNTIL DBUF FULL
JNZ WTB2
CALL WRITE ;WRITE FULL DBUF TO DISK
XTHL ;TOP OF STACK POINTS TO DBUF
LXI H,DBUF
XTHL
JMP WTB1 ;LOOP UNTIL END OF TBUF
WTB3: POP H ;HL POINTS TO CURRENT PLACE IN DBUF
WTB4: MVI M,'Z'-100Q ;STORE EOF CODE
INX H
DCR C ;LOOP THRU REST OF DBUF
JNZ WTB4
CALL WRITE ;WRITE LAST SECTOR TO DISK
CALL CLOSE ;CLEAN UP ACT AND GO HOME
MVI A,BEL ;RING BELL TO LET CLONE
CALL WCC ; KNOW WE'RE THROUGH
RET
WTB5: LXI H,WTBS1 ;PRINT 'TEXT BUFFER EMPTY'
CALL WCS
RET
WTB6: LXI H,WTBS2 ;PRINT 'FILE NAME ERROR'
CALL WCS
RET
WTBS1: DB 'TEXT BUFFER EMPTY',CR,LF,0
WTBS2: DB 'FILE NAME ERROR',CR,LF,0
; WCS - WRITE CONSOLE STRING
;
; ENTRY CONDITIONS
; ?'#ƒÇƒ $!ƒ ƒ $!0ƒç0 ƒ9ƒ0 ƒ90äα߃α߃ 8üƒƒƒƒƒ ƒƒƒƒ<â α߃ƒƒƒƒƒƒƒƒƒ$!ƒƒƒƒ'α߃ƒƒƒƒƒƒƒƒƒ <ƒƒƒƒ<α߃ƒƒƒƒƒƒƒƒƒ α߃ƒƒƒƒƒƒƒƒƒ8<##ƒƒƒ 88α߃ƒƒƒƒƒƒƒƒƒ! ƒƒƒƒ 8α߃αßǃƒƒƒƒƒƒƒƒ 88 ƒÇƒ $0ƒ8 ! #0ƒ8< $<00ƒ 0 !ƒç<!3ƒ#$!0ƒ1003äα߃α߃ 88 üƒƒƒƒ $ƒƒƒƒ<â8 α߃ƒƒƒƒƒƒƒƒƒ8<##ƒƒƒ 88α߃ƒƒƒƒƒƒƒƒƒ $ƒƒƒƒ<â#1α߃αßǃƒƒƒƒƒƒƒƒ 88ƒÇƒ $0ƒ8 ! #0ƒ8'< <80 αßÇαßǃƒƒƒƒƒƒƒƒ0! ƒ8 !3$$ !üαßǃƒƒƒƒƒƒƒƒƒƒƒ<ƒÇƒ8'< <80 ƒ ƒ $0α߃α߃ 88üƒƒƒƒƒ 'ƒƒƒSW
IN CONS
ANI CTBE
JZ $-4
POP PSW
OUT COND
RET
; RCS - READ CONSOLE STRING (WITH ECHO)
;
; EXIT CONDITIONS
; B - NUMBER OF CHARACTERS READ (<255)
; HL - POINTS TO LAST CHAR STORED (CR)
RCS: LXI H,IBUF
MVI B,0
RCS1: CALL RCC ;READ NEXT CHAR FROM CONSOLE
CPI DEL ;JUMP IF NOT DEL
JNZ RCS2
INR B ;IGNORE DEL IF IBUF ALREADY EMPTY
DCR B
JZ RCS1
DCX H ;ELSE DISCARD LAST CHAR
MOV A,M ;ECHO DISCARDED CHAR TO CONSOLE
CALL WCC
DCR B ;DECREMENT COUNT
JMP RCS1 ; AND LOOP
RCS2: CPI 'U'-100Q ;JUMP IF NOT CONTROL-U
JNZ RCS3
CALL WCCR ;ELSE ABORT CURRENT LINE
JMP RCS ; AND START OVER
RCS3: CALL WCC ;ECHO CHAR TO CONSOLE
MOV M,A ;STORE CHAR IN IBUF
INR B ;INCREMENT COUNT
CPI CR ;JUMP IF CARRIAGE RETURN
JZ RCS4
INX H ;ELSE ADVANCE POINTER
JMP RCS1 ; AND LOOP
RCS4: MVI A,LF ;ISSUE LINE FEED AND RETURN
CALL WCC
RET
; RCC - READ CONSOLE CHARACTER
;
; EXIT CONDITIONS
; A - CHARACTER READ
RCC: IN CONS
ANI CRDA
JZ $-4
IN COND
ANI 177Q
RET
; WMC - WRITE MODEM CHARACTER
;
; ENTRY CONDITIONS
; A - CHARACTER TO WRITE
WMC: PUSH PSW
IN MODS
ANI MTBE
JZ $-4
POP PSW
OUT MODD
RET
; RMC - READ MODEM CHARACTER
;
; EXIT CONDITIONS:
; A - CHARACTER READ
RMC: IN MODS
ANI MRDA
JZ $-4
IN MODD
ANI 177Q
RET
; GFN - GET FILE NAME
GFN: CALL WCCR
LXI H,GFNS1 ;PRINT 'FILENAME? '
CALL WCS
CALL RCS ;READ RESPONSE INTO IBUF
LXI H,FCB+FN ;BLANK FILL FN AND FT FIELDS
MVI C,11
GFN1: MVI M,' '
INX H
DCR C
JNZ GFN1
LXI H,IBUF ;POINT TO INPUT BUFFER
LXI D,FCB+FN ;SCAN OFF FN FIELD
MVI C,9
GFN2: MOV A,M ;FETCH NEXT CHAR FROM IBUF
INX H
CPI 141Q ;IF LC, CONVERT TO UC
JC $+5
SUI 40Q
CPI CR ;JUMP IF END OF LINE
JZ GFN5
CPI '.' ;JUMP IF END OF NAME
JZ GFN3
STAX D ;ELSE STORE CHAR IN FN FIELD
INX D
DCR C ;LOOP IF 8 OR LESS CHARS SO FAR
JNZ GFN2
JMP GFN6 ;ELSE TAKE ERROR EXIT
GFN3: LXI D,FCB+FT ;SCAN OFF FT FIELD
MVI C,4
GFN4: MOV A,M ;FETCH NEXT CHAR FROM IBUF
INX H
CPI 141Q ;IF LC, CONVERT TO UC
JC $+5
SUI 40Q
CPI CR ;JUMP IF END OF LINE
JZ GFN5
STAX D ;ELSE STORE CHAR IN FT FIELD
INX D
DCR C ;LOOP IF 3 OR LESS CHARS SO FAR
JNZ GFN4
JMP GFN6 ;ELSE TAKE ERROR EXIT
GFN5: STC ;CLEAR ERROR FLAG AND RETURN
CMC
RET
GFN6: STC ;SET ERROR FLAG AND RETURN
RET
GFNS1: DB 'FILENAME? ',0
; OPEN - OPEN DISK FILE
OPEN: PUSH H
PUSH D
PUSH B
LXI D,FCB
MVI C,OFFC
CALL BDOS
POP B
POP D
POP H
RET
; READ - READ RECORD FROM DISK FILE
READ: PUSH H
PUSH D
PUSH B
LXI D,FCB
MVI C,RRFC
CALL BDOS
POP B
POP D
POP H
RET
; CLOSE - CLOSE DISK FILE
CLOSE: PUSH H
PUSH D
PUSH B
LXI D,FCB
MVI C,CFFC
CALL BDOS
POP B
POP D
POP H
RET
; DELT - DELETE DISK FILE
DELT: PUSH H
PUSH D
PUSH B
LXI D,FCB
MVI C,DFFC
CALL BDOS
POP B
POP D
POP H
RET
; WRITE - WRITE RECORD TO DISK
WRITE: PUSH H
PUSH D
PUSH B
LXI D,FCB
MVI C,WRFC
CALL BDOS
POP B
POP D
POP H
RET
; MAKE - MAKE NEW DISK FILE
MAKE: PUSH H
PUSH D
PUSH B
LXI D,FCB
MVI C,MFFC
CALL BDOS
POP B
POP D
POP H
RET
; DATA AREA
MCB: DS 1 ;MODEM CONTROL BYTE
INCH: DS 1 ;INPUT CHAR BUFFER (TO CYBER)
OUTCH: DS 1 ;OUTPUT CHAR BUFFER (FROM CYBER)
OLDSP: DS 2 ;OLD STACK POINTER
STACK: DS 64 ;LOCAL STACK
IBUF: DS 256 ;INPUT BUFFER
; TEXT BUFFER
FLAG: DS 1 ;TEXT SAVE FLAG
PTR: DS 2 ;TEXT BUFFER POINTER
SIZE: DS 2 ;TEXT BUFFER SIZE
TBUF EQU $ ;START OF TEXT BUFFER
NUM EQU TBUF ;TEMPORARY BUFFER FOR PHONE NUMBER
END LINK
STA INCH
STA OUTCH
STA FLAG ;CLEAR TEXT SAVE FLAG
LXI H,TBUF