TITLE 'MODEM - PL/1 DC HAYES MODEM SUBROUTINES' ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; MODEM I/O AND CONTROL SUBROUTINES FOR DC HAYES MODEM ; (ADAPTED FROM MICROMODEM 100 PROGRAM) ; (ADAPTED AGAIN TO RUN WITH PL/1 ON AUGUST 30, 1980) ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ASSEMBLER STUFF NAME 'MODEM' MODEM: CSEG FALSE: EQU 0 ;TRUE/FALSE SUBSTITUTIONS TRUE: EQU NOT FALSE ; PORT ASSIGNMENTS DATA EQU 80H ;DATA I/O PORT STAT EQU DATA+1 ;STATUS PORT MODE EQU DATA+2 ;MODE CONTROL PORT CR1 EQU DATA+1 ;CONTROL REG 1 CR2 EQU DATA+2 ;CONTROL REG 2 CR3 EQU DATA+3 ;CONTROL REG 3 ; BIT FUNCTIONS ;STATUS REGISTER RRF EQU 001H ;RECEIVE REGISTER FULL TRE EQU 002H ;TRANSMITTER HOLDING REGISTER EMPTY PE EQU 004H ;PARITY ERROR FE EQU 008H ;FRAMING ERROR OE EQU 010H ;DATA OVERRUN ERROR TMR EQU 020H ;TIMER STATUS CD EQU 040H ;CARRIER PRESENT RI EQU 080H ;NOT RING INDICATOR (LOW TRUE) ;CONTROL REGISTER 1 (CR1) EPE EQU 001H ;EVEN PARITY ENABLE LS1 EQU 002H ;WORD LENGTH SELECT BIT 1 LS2 EQU 004H ;WORD LENGTH SELECT BIT 2 SBS EQU 008H ;STOP BITS PI EQU 010H ;PARITY INHIBIT TMIE EQU 020H ;TIMER INTERRUPTS ENABLE ;CONTROL REGISTER 2 (CR2) BRS EQU 001H ;BAUD RATE CONTROL TXE EQU 002H ;TRANSMIT CARRIER ENABLE MS EQU 004H ;MODE (0=ANSWER 1=ORIGINATE) BRK EQU 008H ;SEND BREAK ST EQU 010H ;SELF TEST TIE EQU 020H ;TRANSMITTER INTERRUPT ENABLE RIE EQU 040H ;RECEIVER INTERRUPT ENABLE OH EQU 080H ;OFF-HOOK ; * * * RESET MODEM * * * MDMRST: PUBLIC MDMRST XRA A ;ZERO CONTROL REGS. OUT CR1 OUT CR2 STA MICR1 ; AND MEMORY IMAGES OF REGISTERS. STA MICR2 RET ; * * * TRANSMIT CHAR * * * ; THIS ROUTINE SENDS A BYTE IN REGISTER C TO THE MODEM ; TRANSMITTER. ONLY REGISTER A IS DISTURBED. MDMTXC: PUBLIC MDMTXC CALL PLICHR ;GET THE CHAR TO OUTPUT. MDMTXC$DIR: IN STAT ;GET MODEM STATUS. ANI TXE ;XMIT BUFFER EMPTY? JZ MDMTXC$DIR ;...YES, LOOP. MOV A,C ;...NO, SEND THE BYTE. OUT DATA RET ; * * * RECEIVE CHAR * * * ; THIS ROUTINE RECEIVES A BYTE FROM THE MODEM RECEIVER ; IN REGISTER A. MDMRXC: PUBLIC MDMRXC IN STAT ;GET MODEM STATUS. ANI RRF ;RECV BUFFER EMPTY? JZ MDMRXC ;...YES, LOOP. IN DATA ;...NO, GET DATA. ANI 07FH ;STRIP PARITY. RET ; * * * GET RECV STATUS * * * ; THIS ROUTINE RETURNS A=TRUE IF A RECEIVED CHARACTER ; IS WAITING OR A=FALSE IF NOT. MDMRXS: PUBLIC MDMRXS IN STAT ;GET MODEM STATUS. ANI RRF ;RECV BUFFER EMPTY? MVI A,FALSE RZ ;...YES, RETURN A=FALSE. MVI A,TRUE ;...NO, RETURN A=TRUE RET ; * * * CHECK CARRIER STATUS * * * ; THIS ROUTINE RETURNS TRUE IF CARRIER IS PRESENT. MDMCDS: PUBLIC MDMCDS IN STAT ;GET MODEM STATUS. ANI CD ;CARRIER DETECTED? MVI A,FALSE RZ ;...NO. MVI A,TRUE ;...YES. RET ; * * * CHECK RING STATUS * * * ; THIS ROUTINE CHECKS FOR PHONE RINGING RETURNING ; TRUE IF SO. MDMRIS: PUBLIC MDMRIS IN STAT ;GET MODEM STATUS. ANI RI ;PHONE RINGING? MVI A,TRUE RZ ;...YES. MVI A,FALSE RET ; * * * CHECK FOR MODEM ERROR * * * ; THIS ROUTINE RETURNS THE MODEM ERROR FLAGS IN ; REGISTER A. A=0 IF NO ERRORS. OTHERWISE, ; BIT 0 = PARITY ERROR BIT 1 = FRAMING ERROR ; BIT 2 = OVERRUN ERROR MDMERR: PUBLIC MDMERR IN STAT ;GET MODEM STATUS. RAR ;SHIFT BITS RIGHT 2 PLACES. RAR ANI 7 ;KILL UNWANTED BITS. RET ; * * * CARRIER CONTROL * * * ; THIS ROUTINE TURNS THE CARRIER ON/OFF ACCORDING ; TO REGISTER C. C=FALSE FOR OFF; C=TRUE FOR ON. MDMCRC: PUBLIC MDMCRC CALL PLICHR ;GET THE COMMAND. MDMCRC$DIR: MOV A,C ORA A MVI A,TXE ;CARRIER CONTROL BIT. JZ MDMCC2 ;CLEAR IT IF A=FALSE. JMP MDMSC2 ;SET IT IF A=TRUE. ; * * * BAUD RATE CONTROL * * * ; THIS ROUTINE SETS THE BAUD RATE GIVEN BY REGISTER ; C. C=FALSE FOR 110; C=TRUE FOR 300. MDMBDC: PUBLIC MDMBDC CALL PLICHR ;GET THE COMMAND. MDMBDC$DIR: MOV A,C ORA A MVI A,BRS ;BAUD RATE SELECT BIT. JZ MDMCC2 ;CLEAR IT IF A=FALSE. JMP MDMSC2 ;SET IT IF A=TRUE. ; * * * HOOK CONTROL * * * ; THIS ROUTINE SETS THE HOOK ON OR OFF ACCORDING ; TO REGISTER C. C=FALSE FOR ON (IDLE); C=TRUE ; FOR OFF (ACTIVE). MDMSWH: PUBLIC MDMSWH CALL PLICHR ;GET THE COMMAND. MDMSWH$DIR: MOV A,C ORA A MVI A,OH ;HOOK CONTROL BIT. JZ MDMCC2 ;CLEAR IT IF A=FALSE. JMP MDMSC2 ;SET IT IF A=TRUE. ; * * * GET HOOK STATUS * * * ; THIS ROUTINE RETURNS THE HOOK STATUS IN REGISTER ; A. A=TRUE FOR OFF-HOOK; A=FALSE FOR ON-HOOK. MDMSHS: PUBLIC MDMSHS LDA MICR2 ;GET CR2. ANI OH ;MASK FOR OFF-HOOK. MVI A,TRUE RNZ ;...OFF-HOOK. MVI A,FALSE ;...ON-HOOK. RET ; * * * MODE CONTROL * * * ; THIS ROUTINE SETS THE MODE (ANSWER OR ORIGINATE) ; ACCORDING TO REGISTER C. C=FALSE FOR ANSWER; ; C=TRUE FOR ORIGINATE. MDMMOD: PUBLIC MDMMOD CALL PLICHR ;GET THE COMMAND. MDMMOD$DIR: MOV A,C ORA A MVI A,MS ;MODE SELECT BIT. JZ MDMCC2 ;CLEAR IT IF A=FALSE. JMP MDMSC2 ;SET IT IF A=TRUE. ; * * * SELF-TEST CONTROL * * * ; THIS ROUTINE SETS THE SELF-TEST MODE ; ACCORDING TO REGISTER C. C=FALSE FOR NORMAL; ; C=TRUE FOR SELF-TEST. MDMSLT: PUBLIC MDMSLT CALL PLICHR ;GET THE COMMAND. MDMSLT$DIR: MOV A,C ORA A MVI A,ST ;SELF TEST BIT. JZ MDMCC2 ;CLEAR IT IF A=FALSE. JMP MDMSC2 ;SET IT IF A=TRUE. ; * * * SEND BREAK * * * ; THIS ROUTINE SENDS A BREAK CONSISTING OF A ; SPACE (LOW TONE) FOR A NUMBER OF 50 MS IN- ; TERVALS SPECIFIED BY REGISTER C. MDMBRK: PUBLIC MDMBRK CALL PLICHR ;GET # OF INTERVALS. MDMBRK$DIR: PUSH B MVI C,2 ;WAIT 100 MS. CALL MDMDLY$DIR POP B PUSH H ;SET THE BREAK BIT. LXI H,MICR2 MVI A,BRK ORA M OUT CR2 CALL MDMDLY$DIR ;DELAY (C)*50 MS. MVI A,BRK ;RESET BREAK BIT. CMA ANA M OUT CR2 POP H RET ; * * * SET PARITY * * * ; THIS ROUTINE SETS THE PARITY ACCORDING TO REG C. ; C=0 FOR NO PARITY, C=1 FOR ODD PARITY AND C=2 ; FOR EVEN PARITY. MDMPAR: PUBLIC MDMPAR CALL PLICHR ;GET THE COMMAND. MDMPAR$DIR: MOV A,C ;TEST FOR NO PARITY. ORA A JZ MDMPAF ;TURN OFF PARITY. MVI A,PI ;CLEAR PARITY INHIBIT BIT. CALL MDMCC1 MOV A,C ;SET LSB FOR EVEN/ODD PARITY. RAR ANI 1 MVI A,EPE ;CLEAR EPE IF ODD. JZ MDMCC1 JMP MDMSC1 ;SET EPE IF EVEN. MDMPAF: MVI A,PI ;INHIBIT PARITY. JMP MDMSC1 ; * * * SELECT WORD LENGTH * * * ; THIS ROUTINE SETS THE WORD LENGTH ACCORDING TO REG C. ; C = NUMBER OF BITS (5,6,7,8) MDMWLN: PUBLIC MDMWLN CALL PLICHR ;GET THE COMMAND. MDMWLN$DIR: MOV A,C ;REMOVE BIAS. SUI 5 RC CPI 3+1 CMC RC ADD A ;SHIFT LEFT 1 PLACE. MOV C,A ;SAVE RESULT. LDA MICR1 ;GET MEMORY IMAGE. ANI NOT LS1+LS2 ;CLEAR WORD LENGTH BITS. ORA C ;PUT IN NEW ONES. STA MICR1 ;UPDATE MEMORY IMAGE. OUT CR1 ;WRITE IT TO MODEM. RET ; * * * SET NUMBER OF STOP BITS * * * ; THIS ROUTINE SETS THE NUMBER OF STOP BITS ACCORDING ; TO REGISTER C. C = STOP BITS (1 OR 2) MDMNST: PUBLIC MDMNST CALL PLICHR ;GET THE COMMAND. MDMNST$DIR: MOV A,C ;REMOVE BIAS. SUI 1 RC CPI 1+1 CMC RC ORA A MVI A,SBS ;STOP BIT SELECT BIT. JZ MDMCC1 ;CLEAR IT. JMP MDMSC1 ; * * * DELAY ROUTINE * * * ; THIS ROUTINE WAITS 50MS TIMES THE VALUE OF THE ; REGISTER C. MDMDLY: PUBLIC MDMDLY CALL PLICHR ;GET THE TIME AMOUNT. MDMDLY$DIR: MOV A,C ORA A ;IF ZERO, DON'T WAIT. RZ PUSH B MDMDL1: OUT CR3 ;START TIMER. MDMDL2: IN STAT ;WAIT TILL TIMER BIT ANI TMR ;TIMES OUT. JZ MDMDL2 DCR C ;LOOP (C) TIMES. JNZ MDMDL1 POP B RET ; * * * START 50MS TIMER * * * MDMSTM: PUBLIC MDMSTM OUT CR3 RET ; * * * CHECK TIMER STATUS * * * MDMCTM: IN STAT ;GET MODEM STATUS. ANI TMR ;TIME OUT? MVI A,TRUE RNZ ;...YES. MVI A,FALSE RET ; * * * GO OFF HOOK * * * ; THIS ROUTINE GOES OFF HOOK AND WAITS FOR A DIAL TONE. ; MICROMODEM HAS NO DIAL TONE DETECTOR. WE JUST GO OFF ; HOOK, WAIT 2 SEC, ASSUME A DIAL TONE IS PRESENT AND ; RETURN. MDMDLT: PUBLIC MDMDLT PUSH B MVI C,TRUE ;GO OFF-HOOK. CALL MDMSWH$DIR MVI C,40 ;WAIT 2 SECONDS. CALL MDMDLY$DIR POP B RET ; * * * DIAL PULSE GENERATION * * * ; THIS ROUTINE GENERATES A DIALING PULSE FOR THE DIGIT ; IN REGISTER C. IF C=0 THEN 10 PULSES WILL BE ; PRODUCED. THE DIGIT IN THE C REGISTER MAY BE ; BINARY OR ASCII. AFTER THE DIGIT IS OUT-PULSED, ; THIS ROUTINE WILL PAUSE FOR 600 MS FOR INTER-DIGIT ; SPACING. MDMPLS: PUBLIC MDMPLS CALL PLICHR ;GET THE DIGIT. MDMPLS$DIR: PUSH B MOV A,C ;GET DIGIT. MVI B,10 ;PRE-LOAD PULSE COUNTER ANI 00FH ;KILL POSSIBLE ASCII BIAS. CPI 0 ;SEE IF WE'RE DOING 10 PULSES. JZ MDMPL1 MOV B,A ;PULSE COUNT TO B MDMPL1: MVI C,FALSE ;GO ON-HOOK. CALL MDMSWH$DIR MVI C,1 ;WAIT 50 MS. CALL MDMDLY$DIR MVI C,TRUE ;GO OFF-HOOK AGAIN. CALL MDMSWH$DIR MVI C,1 ;DELAY 50 MS. CALL MDMDLY$DIR DCR B ;LOOP FOR ALL PULSES. JNZ MDMPL1 MVI C,11 ;WAIT 550 MS. CALL MDMDLY$DIR POP B RET ; * * * DIAL A NUMBER * * * ; THIS ROUTINE GENERATES ALL THE DIALING PULSES ; FOR A NUMBER GIVEN AS A VARYING CHARACTER STRING. ; THEREFORE, IT DIALS THE NUMBER. MDMDLN: PUBLIC MDMDLN CALL MDMDLT ;GET DIAL TONE. CALL PLICHR ;GET THE STRING LENGTH IN C. ORA A ;LENGTH=ZERO? RZ ;...YES, RETURN. INX H ;BUMP TO BEGINNING OF STRING. MDMDLN$LP: MOV A,M ;GET THE NEXT NUMBER. CPI '*' ;DELAY? JNZ MDMDLN$NUM ;...YES. PUSH B MVI C,40 ;WAIT 2 SEC. CALL MDMDLY$DIR POP B JMP MDMDLN$NXT ; GET NEXT CHAR. MDMDLN$NUM: CPI '9'+1 ;ASCII 0-9? JNC MDMDLN$NXT ;...NO, SKIP IT. CPI '0' JC MDMDLN$NXT ;...NO, SKIP IT. PUSH B ;SAVE CURRENT COUNT. MOV C,A ;PULSE OUT THE NUMBER. CALL MDMPLS$DIR POP B MDMDLN$NXT: INX H ;BUMP PTR. DCR C ;DECREMENT COUNT. RZ ;RETURN IF NO MORE DIGITS. JMP MDMDLN$LP ;GO PULSE ANOTHER DIGIT. ; * * * SET CR1 * * * ; THIS ROUTINE SETS BITS IN CONTROL REGISTER ; 1. REGISTER A HAS 1'S WHERE BITS ARE TO ; BE SET. MDMSC1: PUSH H LXI H,MICR1 ;OR IN BITS TO SET. ORA M MOV M,A ;SAVE RESULT. OUT CR1 ;SET THE MODEM. POP H RET ; * * * CLEAR CR1 * * * ; THIS ROUTINE CLEARS THE BITS IN CONTROL REGISTER ; 1. REGISTER A HAS 1'S FOR THE BITS TO BE CLEARED. MDMCC1: PUSH H LXI H,MICR1 ;MEMORY IMAGE OF CR1. CMA ANA M ;TURN OFF THE BIT. MOV M,A ;UPDATE MEMORY. OUT CR1 ;UPDATE MODEM. POP H RET ; * * * SET CR2 * * * ; THIS ROUTINE SETS BITS IN CONTROL REGISTER ; 2. REGISTER A HAS 1'S WHERE BITS ARE TO ; BE SET. MDMSC2: PUSH H LXI H,MICR2 ;OR IN BITS TO SET. ORA M MOV M,A ;SAVE RESULT. OUT CR2 ;SET THE MODEM. POP H RET ; * * * CLEAR CR2 * * * ; THIS ROUTINE CLEARS THE BITS IN CONTROL REGISTER ; 2. REGISTER A HAS 1'S FOR THE BITS TO BE CLEARED. MDMCC2: PUSH H LXI H,MICR2 ;MEMORY IMAGE OF CR2. CMA ANA M ;TURN OFF THE BIT. MOV M,A ;UPDATE MEMORY. OUT CR2 ;UPDATE MODEM. POP H RET ; * * * GET PL/I PARAMETER * * * ; THIS ROUTINE GETS A PL/I PARAMETER ACCORDING TO ; ITS STANDARD CALLING CONVENTIONS. PLICHR: PUSH D ;SAVE DE. MOV E,M ;GET PARM PTR FROM 0(HL). INX H MOV D,M LDAX D ;GET THE ONE BYTE PARM. MOV C,A ;PUT IT IN (C). XCHG ;PUT PARM PTR IN HL. POP D RET ; * * * DATA AREA FOR MODEM I/O * * * DSEG MICR1: DB 0 ;MEMORY IMAGE OF CONTROL REGISTER 1 MICR2: DB 0 ;MEMORY IMAGE OF CONTROL REGISTER 2 END