TITLE 'MICROMODEM 100 TERMINAL PROGRAM' ; WRITTEN BY DALE A. HEATHERINGTON ; VER. 1.11 6-26-79 ;80-103A TIMER ROUTINE ADDED ;SEE THE MODEM I/O SECTION ;SPECIAL MODS FOR 80-103A INSTALLED 7-26-79 *** MM100 EQU 0 ;SET TO 1 FOR MM100 CODE ;OR SET TO ZERO FOR 80-103A CODE MHZ EQU 2 ;THIS IS THE CPU SPEED. ;IF YOU HAVE 4 MHZ CPU SET IT TO 4 ;THIS HAS NO EFFECT IF MICROMODEM 100 ;CODE IS ASSEMBLED. ORG 100H CPM EQU 1 ;SET FOR CPM ASSEMBLY BDOS EQU 5 ;CPM ENTRY REBOOT EQU 0 ;CPM WARM BOOT CR EQU 0DH ;CARRAGE RETURN LF EQU 0AH ;LINE FEED BELL EQU 7 ;ASCII BELL START: LXI SP,STACK CALL INIT ;SET UP CP/M I/O VECTORS LXI D,PROMPT ;PUSH A RETURN ADDRESS ON STACK PUSH D ;IN CASE CARRIER IS PRESENT CALL CDSTAT ;SEE IF WE GOT CARRIER ORA A JZ STR1 ;NO, DO INITIALIZATION CALL CKRAM ;GET CHECKSUM OF RAM AREA MOV C,A LDA CKSUM ;GET OLD CHECKSUM CMP C ;SAME? JZ TALK ;RAM OK, JUMP TO COMM LOOP CALL PRINT DB 'REENTRY NOT POSSIBLE, RAM OVERWRITTEN',CR STR1: CALL RESET ;ELSE CLEAR MODEM LDA 7 ;GET PAGE ADDRESS OF CP/M SUI 1 ;1 PAGE BELOW IT STA MTOP ;TOP OF USER MEMORY CALL CRLF CALL PRINT DB ' D.C. Hayes Associates, Inc.',CR CALL PRINT IF MM100 DB 'Micromodem 100 Terminal program ver. 1.11',CR ELSE DB '80-103A Terminal program ver. 1.11',CR ENDIF XRA A ;A=0 STA NMBR ;SET PHONE NUMBER BUFFER EMPTY LXI H,DFAULT ;POINT TO COMMAND STRING SHLD BUFPNT ;OF DEFAULT OPTIONS CALL DEC1 ;EXECUTE THE COMMANDS POP D ;CLEAN UP STACK PROMPT: CALL CMND ;GET AND EXECUTE COMMANDS JMP PROMPT ;LOOP FOREVER ;THIS IS A COMMAND LINE THAT SETS THE DEFAULT OPTIONS. ;8 DATA BITS, 1 STOP BIT, NO PARITY, 300 BAUD, FULL DUPLEX, ;CLEAR CAPTURE BUFFER. SET DEBUG MODE OFF. DFAULT: DB 'L8,S1,PN,B3,F,C0,?0',CR ;DOES A CHECKSUM OF THE SCRATCH PAD RAM LOCATIONS CKRAM: MVI B,EOR-SOR ;END OF RAM MINUS START OF RAM = COUNT LXI H,SOR ;START OF RAM POINTER MVI A,0 ;A IS CHECKSUM CKR1: ADD M ;ADD MEMORY BYTE INX H ;INC. POINTER DCR B ;COUNT 'EM JNZ CKR1 ;LOOP IF NOT DONE RET ;CHECKSUM IN REG A ;THIS ROUTINE FILLS THE COMMAND BUFFER WITH ;A COMMAND STRING FROM THE CONSOLE THEN ;DECODES AND EXECUTES THEM. CMND: CALL CRLF CALL PRINT DB 'COMMAND:@' CALL FILBUF ;GET COMMANDS TO BUFFER ORA A ;TEST FOR NO COMMANDS RZ ;RETURN IF NONE IN BUFFER DECODE: LXI H,BUF ;POINT TO COMMAND BUFFER SHLD BUFPNT ;SAVE POINTER DEC1: CALL NEXT ;GET A COMMAND CPI CR ;END OF LINE? RZ ORA A ;DELIMITER? JZ DEC1 LXI H,TABLE ;POINT TO DECODE TABLE MOV C,A ;STORE COMMAND IN C SRCH: MOV A,M ;GET BYTE FROM TABLE CMP C ;DOES IT MATCH? JZ FOUND ;YES, JUMP INX H ;NO, ADVANCE POINTERS INX H INX H ORA A ;TEST FOR END OF TABLE JNZ SRCH CALL CONOUT ;ECHO BAD COMMAND CALL PRINT DB ' = BAD COMMAND',CR RET FOUND: LXI D,DEC1 ;RETURN ADDRESS PUSH D ;PUT IT ON STACK INX H MOV E,M ;GET LOW BYTE OF COMMAND ADR. INX H MOV D,M ;GET HIGH BYTE XCHG ;ADDRESS TO HL PCHL ;CALL ROUTINE ;THIS ROUTINE GETS CHARACTERS FROM THE CONSOLE ; AND PUTS THEM IN A BUFFER. RUBOUT WILL DELETE ; THE LAST CHARACTER TYPED. CONTROL U WILL KILL ; THE WHOLE LINE. THE BUFFER IS 64 CHARACTERS ; LONG. FILBUF: LXI H,BUF MVI B,0 ;CHARACTER COUNTER FIL1: CALL CONIN ;GET ONE CPI 7FH ;IS IT A RUBOUT? FIL2: JNZ FIL3 ;JUMP IF NOT MOV A,B ORA A ;SEE IF BUFFER EMPTY JZ FILBUF DCX H DCR B ;BACK UP EVERYTHING MVI C,5FH ;BACK ARROW CHARACTER CALL CONOUT JMP FIL1 FIL3: CPI 15H ;CONTROL U? JNZ FIL4 MVI C,'#' CALL CONOUT ;ECHO # CALL CRLF XRA A RET ;RETURN A=0 FIL4: CPI CR ;CARRAGE RETURN JNZ FIL5 MOV M,A ;PUT IT IN BUFFER MOV A,B ;GET COUNT CALL CRLF RET FIL5: CALL UCASE ;CONVERT TO UPPER CASE MOV M,A ;PUT IT IN MEMORY MOV C,A MVI A,64 ;MAX. LENGTH OF BUFFER CMP B JNZ FIL6 ;JUMP IF NOT FULL MVI C,'#' JMP FIL7 FIL6: INX H INR B ;ADVANCE POINTER AND COUNTER FIL7: CALL CONOUT ;ECHO CHARACTER JMP FIL1 ;LOWER TO UPPER CASE CONVERSION ROUTINE. UCASE: CPI 60H RC ;RETURN IF ALREADY UPPER CASE SUI 20H ;ELSE CONVERT TO UPPER RET ;THIS ROUTINE GETS THE NEXT CHARACTER FROM THE BUFFER. ;IT RETURNS A=0 IF A COMMA OR SPACE IS ENCOUNTERED. NEXT: LHLD BUFPNT ;GET ADDRESS OF BUFFER MOV A,M ;GET A BYTE INX H SHLD BUFPNT ;INCREMENT AND SAVE POINTER CPI 20H ;SPACE? JZ DELM CPI ',' ;COMMA? JZ DELM CPI CR ;CARRAGE RETURN? RNZ ;RETURN IF NOT DCX H SHLD BUFPNT RET DELM: XRA A RET ;THIS ROUTINE ADVANCES THE BUFFER POINTER TO THE ;NEXT COMMAND OR DIGIT STRING. ;IF NO MORE CHARACTERS WERE FOUND IT WILL RETURN ;WITH A=0. OTHERWISE A=1 NXTCHR: CALL NEXT MVI C,0 CPI CR ;TEST FOR END OF BUFFER JZ NXT1 ORA A ;TEST FOR DELIMITER JZ NXTCHR ;JUMP IF SPACE OR COMMA INR C ;C = 1 LHLD BUFPNT ;GET BUFFER POINTER DCX H ;BACK UP ONE SHLD BUFPNT ;STORE IT NXT1: MOV A,C ;A=0 NONE FOUND RET ;A=1 CHARACTER FOUND ;GET A HEX DIGIT STRING FROM BUFFER AND ;CONVERT IT TO A 16 BIT BINARY NUMBER IN DE. GETHEX: LXI H,0 GH1: XCHG ;NUMBER TO DE CALL NEXT ;GET A DIGIT CPI '0' ;SEE IF IT'S HEX RC ;RETURN ON FIRST NON HEX CHAR. CPI 'G' RNC CPI 'A' JNC GH2 CPI ':' RNC GH2: SUI 30H ;REMOVE ASCII BIAS CPI 10 JC GH3 ;JUMP IF DIGIT 0-9 SUI 7 ;ELSE REMOVE A-F BISAS GH3: XCHG ;NUMBER TO HL DAD H ;SHIFT LEFT 4 BITS DAD H DAD H DAD H ADD L ;ADD IN THIS DIGIT MOV L,A JMP GH1 ;SEND CARRAGE RETURN-LINE FEED TO CONSOLE CRLF: CALL PRINT DB CR RET ;PRINTS A STRING POINTED TO BY CONTENTS OF TOP ; OF STACK. CARRAGE RET. OR "@" TERMINATES THE STRING. ; "@" WILL PRINT STRING WITH NO CR-LF SEQUENCE AT END. PRINT: XTHL ;TOP OF STACK TO HL PUSH PSW ;SAVE REGISTERS PUSH B PRN1: MOV A,M ;GET A CHARACTER INX H CPI '@' ;END? JZ PRN2 ;JUMP IF END, NO CRLF MOV C,A CALL CONOUT ;PRINT THE CHAR. CPI CR ;WAS IT A CARRAGE RET.? JNZ PRN1 ;NO, GO BACK FOR MORE CALL PRINT ;CALL OURSELF DB LF,0,0,0,'@' ;LINE FEED AND 3 NULLS PRN2: POP B ;RESTORE REGISTERS POP PSW XTHL ;RETURN ADDRESS TO STACK RET ;RETURNS TO USERS OPERATING SYSTEM QUIT: CALL CRLF CALL SHSTAT ;GET SWITCH-HOOK STATUS ORA A JZ REBOOT CALL PRINT DB 'DO YOU WANT TO HANG UP FIRST? (Y OR N)@' CALL CONIN CALL UCASE MOV C,A CALL CONOUT MOV A,C CPI 'N' JNZ QUIT1 CALL CKRAM ;GET CURRENT RAM CHECKSUM STA CKSUM ;SAVE IT JMP REBOOT ;BACK TO CPM QUIT1: CALL HANGUP JMP REBOOT ;THIS ROUTINE DIALS A PHONE NUMBER THEN JUMPS TO ;THE COMMUNICATION ROUTINE. ;IF NO PHONE NUMBER FOLLOWS THE "D" COMMAND THE ;LAST NUMBER DIALED WILL BE RE-DIALED. DIAL: CALL PRINT DB 'DIALING-@' CALL DLTONE ;GET A DIAL TONE CALL NXTCHR ;FIND PHONE NO. IN BUFFER ORA A JZ DL1 ;PHONE NUMBER NOT PRESENT LXI D,NMBR-1 ;POINT TO PHONE NO. BUFFER DL0: CALL NEXT ;GET A DIGIT INX D ;ADVANCE POINTER STAX D ;PUT IT IN BUFFER ORA A JZ DL1 CPI CR JNZ DL0 ;IF NOT END, LOOP BACK XRA A ;A=0 STAX D ;ZERO MARKS END OF NUMBER DL1: LXI H,NMBR ;POINT TO NUMBER BUFFER DL2: MOV A,M ;GET A DIGIT INX H ;ADVANCE POINTER ORA A ;TEST FOR END JZ COMM ;GO TRY TO COMMUNICATE MOV C,A CALL CONOUT ;ECHO DIGIT WE'RE DIALING MOV A,C MVI C,40 CPI '*' ;2 SECOND DELAY? PUSH PSW CZ DELAY ;YES, WAIT 2 SEC. POP PSW JZ DL2 CPI 3AH ;IGNORE ALL XCEPT DIGITS JNC DL2 CPI '0' JC DL2 MOV C,A CALL PULSE ;DIAL THE DIGIT JMP DL2 ;LOOP BACK FOR MORE ;THIS ROUTINE WAITS FOR THE PHONE TO RING. ;IT THEN ANSWERS ON THE FIRST RING, TURNS ON ;THE CARRIER, THEN JUMPS TO "COMM1" AND WAITS ;FOR A RECEIVE CARRIER. ANSWR: CALL NEXT ;GET NEXT CHARACTER CPI 'A' ;A=ANSWER WITHOUT A RING JZ ANS2 ;IN ANSWER MODE CPI 'O' ;O=ANSWER WITHOUT A RING JZ COMM ;IN ORIGINATE MODE CALL PRINT ;ELSE WAIT FOR RING DB 'WAITING FOR RING. PRESS ANY KEY TO ABORT.',CR ANS1: CALL RISTAT ;CHECK FOR PHONE RINGING ORA A JNZ ANS2 ;IF YES THEN ANSWER IT CALL CONST ;ABORT? ORA A JZ ANS1 ;NO, LOOP BACK CALL CONIN ;GET CHARACTER RET ;ABORT ANS2: CALL PRINT DB BELL,'ANSWERING CALL',CR MVI C,1 CALL SWHOOK ;ANSWER PHONE MVI A,0 ;A=0 FOR ANSWER MODE STA MFLAG MOV C,A CALL MODE ;SET TO ANSWER MODE MVI C,1 CALL TXON ;TURN ON TRANSMIT CARRIER JMP COMM1 ;THIS ROUTINE WAITS FOR A CARRIER THEN GOES INTO ;THE TELETYPE MODE FOR COMMUNICATIONS. COMM: CALL CRLF MVI A,1 ;ORIGINATE MODE STA MFLAG ;SET TO MODE MOV C,A CALL MODE COMM1: MVI E,30 ;SET FOR 30 SECONDS CALL PRINT DB 'WAITING FOR CARRIER, PRESS ANY KEY TO ABORT.',CR CM1: MVI C,20 ;FOR 1 SECOND DELAY CALL DELAY ;WAIT A SECOND CALL CDSTAT ;LOOK FOR A CARRIER ORA A ;SET FLAGS JNZ TALK CALL CONST ;CHECK CONSOLE ORA A JNZ CM2 ;ABORT IF ANY KEY PRESSED DCR E ;COUNT SECONDS JNZ CM1 ;LOOP 30 TIMES CM2: CALL PRINT DB 'NO CARRIER RECEIVED',BELL,CR CALL CONST ;CHECK CONSOLE ORA A CNZ CONIN ;THROW AWAY CHARACTER JMP HANGUP ;THIS IS THE COMMUNICATIONS LOOP. CHARACTERS FROM THE ;LINE ARE SENT TO THE CONSOLE. CHRACTERS FROM THE ;CONSOLE ARE SENT TO THE PHONE LINE. TALK: CALL CDSTAT ORA A JZ TLK2 MVI C,1 CALL TXON ;TURN ON CARRIER CALL PRINT DB 'CONNECTION ESTABLISHED',CR TLK1: CALL CONST ;CHECK FOR CONSOLE CHAR. ORA A CNZ CSEND ;SEND IT IF PRESENT CALL RXSTAT ;SEE IF MODEM HAS A CHARn ORA A CNZ CRECV ;GET IT IF PRESENT CALL CDSTAT ;CHECK FOR CARRIER ORA A JNZ TLK1 ;IF CARRIER, CONTINUE TLK2: CALL CRLF CALL PRINT DB '[* LOST CARRIER *]',BELL,CR JMP HANGUP ;SEND A CHARACTER TO MODEM. ;CONSOLE CHARACTERS ARE CHECKED FOR 2 CONTROL CODES. ;CONTROL A WILL ESCAPE TO THE COMMAND MODE. ;CONTROL B WILL CAUSE A BREAK TO BE TRANSMITTED. ;NOTE THAT CONTROL A OR B CAN'T BE SENT TO THE MODEM. CSEND: CALL CONIN ;GET CHAR. FROM CONSOLE CPI 1 ;CONTROL A? JZ CMND ;BACK TO COMMAND MODE MVI C,3 ;PREPARE FOR 150 MS BREAK CPI 17H ;CONTROL W? JZ BREAK ;YES, SEND BREAK MOV C,A XMIT: CALL TXCHR ;SEND TO MODEM LDA MFLAG ;GET MODE 0=ANS 1=ORG ORA A JZ CONOUT ;ECHO IF ANSWER MODE LDA DPLX ;GET DUPLEX FLAG 1=FULL ORA A JZ CONOUT ;ECHO IF HALF DUPLEX RET ;RECEIVES CHARACTERS FROM THE MODEM AND SENDS THEM ; TO THE CONSOLE. IF IN FULL DUPLEX ANSWER MODE THE ; CHARACTERS WILL BE ECHOED BACK TO THE MODEM. IN ; ORIGINATE MODE OR HALF DUPLEX CHARACTERS WILL NOT ;BE ECHOED BACK. ;IT ALSO CALLS THE CAPTURE ROUTINE WHICH WILL PUT ;THE RECEIVED CHARACTERS IN THE BUFFER IF IT IS ENABLED. CRECV: CALL RXCHR ;GET CHARACTER FROM MODEM MOV C,A LDA BUGFLAG ;SEE IF WE PRINT IT IN HEX ORA A JZ REC1 ;JUMP IF NOT HEX DISP. MODE CALL PRNHEX MVI C,20H ;ASCII SPACE CALL CONOUT ;SPACE BETWEEN HEX NUMBERS LDA BUGCOUNT DCR A STA BUGCOUNT ANI 0FH CZ CRLF JMP REC2 REC1: CALL ERFLG ;GER __T ERROR FLAGS ANI 1 JZ REC3 MVI C,'#' ;# SUBS FOR CHAR. WITH PARITY ERROR REC3: MOV A,C ANI 7FH ;KILL MSB MOV C,A CALL CONOUT ;SEND TO CONSOLE REC2: CALL CPBFIL ;ALSO TO CAPTURE BUFFER LDA MFLAG ;GET MODE 1=ORG 0=ANS ORA A RNZ ;DON'T ECHO TO LINE IF ORIG. LDA DPLX ;GET DUPLEX FLAG 1=FULL ORA A JNZ TXCHR ;ECHO BACK TO SENDER RET ;PRINTS INCOMMING CHARACTERS IN HEX WITH THE MODEM STATUS WORD. PRNHEX: PUSH B ;CHARACTER IS IN C, SAVE IT MOV A,C RRC RRC RRC RRC CALL PRNH1 POP B ;RESTORE CHARACTER PUSH B ;SAVE AGAIN MOV A,C CALL PRNH1 ;PRINT LOW NIBBLE POP B RET PRNH1: ANI 0FH ;KEEP LOW 4 BITS ADI 30H ;ASCII BIAS ADDED MOV C,A CPI 3AH JC CONOUT MVI A,7 ADD C ;MAKE LETTER A-F MOV C,A JMP CONOUT ;THIS ROUTINE HANGS UP AND TURNS OFF THE TX CARRIER. HANGUP: MVI C,0 CALL TXON ;TRANSMIT CARRIER OFF MVI C,0 CALL SWHOOK ;GO ON-HOOK CALL PRINT DB '[ HUNG UP ]',BELL,CR MVI C,20 ;SET FOR 1 SECOND DELAY CALL DELAY ;WAIT FOR THINGS TO DISCONNECT RET ;***** THE FOLLOWING ROUTINES SET OPTIONS ****** ;NOTE THAT MOST DON'T CHECK FOR VALID RANGE OF VARIABLES. ;IT IS POSSIBLE FOR EXAMPLE TO SET THE STOP BITS TO 7 OR 9 ;OR OTHER IMPOSSIBLE NUMBER. IN THIS CASE 1 OR 2 STOP BITS ;WOULD ACTUALLY BE SET EVEN THOUGH NO ERROR MESSAGE WAS ;GENERATED. ;THIS ROUTINE LETS THE USER CHANGE THE BAUD RATE. BRATE: CALL GETHEX ;GET A DIGIT MOV A,E CPI 1 ;110 BAUD? JZ BR110 CPI 3 JNZ BADBR ;BAD IF NOT 110 OR 300 CALL PRINT DB '300 BAUD',CR MVI C,1 JMP BAUD ;SET RATE BR110: CALL PRINT DB '110 BAUD',CR MVI C,0 JMP BAUD BADBR: CALL PRINT DB 'BAD BAUD RATE',CR RET ;LETS USER CHANGE LENGTH OF DATA WORD (5,6,7,8 BITS). LENGTH: CALL GETHEX ;GET LENGTH CALL PDIGIT ;PRINT IT CALL PRINT DB ' DATA BITS',CR MOV C,E JMP WLS ;SET MODEM BOARD PDIGIT: MVI A,30H ADD E ;MAKE NUMBER IN E ASCII MOV C,A CALL CONOUT ;PRINT IT RET ;SET NUMBER OF STOP BITS ( 1 OR 2). SBITS: CALL GETHEX CALL PDIGIT CALL PRINT DB ' STOP BITS',CR MOV C,E JMP NSTOP ;SET THE MODEM ;SETS FULL DUPLEX MODE ( F COMMAND) FULL: MVI A,1 STA DPLX ;SET FLAG CALL PRINT DB 'FULL DUPLEX',CR RET ;SET HALF DUPLEX MODE (H COMMAND) HALF: XRA A STA DPLX ;CLEAR FLAG CALL PRINT DB 'HALF DUPLEX',CR RET ;SET PARITY, N=NO PARITY E=EVEN PARITY O=ODD PARITY PARTYP: CALL NXTCHR ;FIND NEXT CHARACTER IN BUFF. CALL NEXT ;GET IT CPI 'N' JZ NPAR CPI 'E' JZ EPAR CPI 'O' JZ OPAR RET NPAR: CALL PRINT DB 'NO PARITY',CR MVI C,0 JMP PARITY EPAR: CALL PRINT DB 'EVEN PARITY',CR MVI C,2 JMP PARITY OPAR: CALL PRINT DB 'ODD PARITY',CR MVI C,1 JMP PARITY ;THIS ROUTINE ALLOWS THE USER TO JUMP TO ;AN EXTERNAL PROGRAM AND EXECUTE IT. ;FOR EXAMPLE, IF YOU HAD A ROM MONITOR ;AT F000 HEX, YOU WOULD ENTER THE COMMAND: J F000 ; JUMP: CALL NXTCHR ;FIND ADDRESS CALL GETHEX ;CONVERT TO BINARY IN DE XCHG ;ADDRESS TO HL PCHL ;JUMP TO ROUTINE ;THIS ROUTINE SETS UP THE THE CAPTURE FUNCTION ;COMMAND FORMAT: C0 RESETS THE BUFFER POINTER ;AND DISABLES CAPTURE. ;C1 ENABLES CAPTURE AT CURRENT BUFFER ADDRESS ;C2 STOPS CAPTURE AT CURRENT ADDRESS. CAPTURE: CALL NXTCHR ;FIND DIGIT ORA A RZ ;RETURN IF NO ARG. CALL NEXT ;GET DIGIT CPI '0' JZ RSBUF ;IF ZERO, RESET CPI '1' JZ STRT ;IF 1 START CAPTURE MODE CPI '2' RNZ ;IF 2 STOP CAPTURE XRA A STA CPFLAG ;CLEAR CAPTURE FLAG CALL PRINT DB 'CAPTURE STOPED',CR RET STRT: MVI A,1 STA CPFLAG ;SET CAPTURE FLAG CALL PRINT DB 'CAPTURE ENABLED',CR RET RSBUF: LXI H,CPBUF ;START OF CAPTURE BUFFER SHLD CBUFP ;STORE POINTER XRA A STA CPFLAG ;CLEAR FLAG STA CPCNT ;CLEAR BYTE COUNTER STA CPCNT+1 CALL PRINT DB 'CAPTURE BUFFER CLEARED',CR RET ;THIS ROUTINE FILLS THE CAPTURE BUFFER WITH CHARACTERS ;FROM THE MODEM IF THE "CPFLAG" IS SET TO A 1. ;THE BUFFER POINTER IS STORED AT "CBUFP". CPBFIL: LDA CPFLAG ;GET FLAG ORA A RZ ;RETURN IF NOT ENABLED PUSH H ;SAVE HL LHLD CBUFP ;GET BUFFER POINTER MOV M,C ;PUT CHARACTER IN BUFFER INX H ;ADVANCE POINTER LDA MTOP ;TOP OF MEMORY CMP H ;CHECK FOR "OUT OF MEMORY" JZ OUTMEM SHLD CBUFP ;SAVE POINTER LHLD CPCNT ;GET CHARACTER COUNTER INX H ;INCREMENT IT SHLD CPCNT ;STORE IT POP H RET OUTMEM: CALL CRLF CALL PRINT DB 'CAPTURE BUFFER FULL',BELL,CR XRA A STA CPFLAG ;DISABLE CAPTURE MODE POP H RET ;TYPES THE CAPTURE BUFFER TO THE CONSOLE. ;T WILL TYPE STARTING AT THE BEGINNING ;T FOLLOWED BY A HEX NUMBER WILL CAUSE PRINTING TO ;START AT A POINT SPECFIED BY THE NUMBER. FOR EXAMPLE ;T 100 WILL START TYPING AT A POINT 100 HEX ;CHARACTERS INTO THE BUFFER. S STARTS ;AND STOPS THE PRINTING. CARRAGE RETURN ABORTS ;THIS FUNCTION. TYPE: CALL GETHEX LXI H,CPBUF ;STARTING ADDRESS OF BUFFER DAD D ;ADD USERS COUNT TO STARTING ADR. TY1: LDA CPCNT ;SEE IF WE'RE AT END CMP E JNZ TY0 LDA CPCNT+1 CMP D RZ ;QUIT AT END OF BUFFER TY0: MOV C,M ;GET A CHARACTER CALL CONOUT ;PRINT IT CALL CONST ;CHECK FOR CONSOLE INPUT ORA A JZ TY2 CALL CONIN ;GET CONSOLE CPI CR ;WANT TO ABORT? RZ ;IF YES THEN RETURN CPI 'S' ;WANT TO STOP? JNZ TY2 TY3: CALL CONST ORA A JZ TY3 ;WAIT FOR ANOTHER S CALL CONIN CPI CR RZ CPI 'S' JNZ TY3 TY2: INX H ;ADVANCE POINTERS INX D JMP TY1 ;LOOP BACK FOR MORE DEBUG: CALL NEXT CPI '0' JZ DBOFF CPI '1' ;DEBUG ON? RNZ CALL PRINT DB 'DEBUG MODE ON',CR MVI A,1 STA BUGFLAG DCR A STA BUGCOUNT RET DBOFF: CALL PRINT DB 'DEBUG MODE OFF',CR XRA A STA BUGFLAG RET ;THIS IS THE COMMAND DECODING TABLE. ;EACH ENTRY IS AN ASCII LETTER FOLLOWED BY AN ADDRESS ;OF THE ROUTINE WHICH IS CALLED TO EXECUTE THAT COMMAND. ;THE END OF THE TABLE IS MARKED WITH A ZERO. TABLE: DB 'X' ;EXIT TO CP/M DW QUIT DB 'D' ;DIAL A NUMBER DW DIAL DB 'A' ;ANSWER CALLS DW ANSWR DB 'G' ;"GOODBYE" HANG UP PHONE DW HANGUP DB 'B' ;CHANGE BAUD RATE DW BRATE DB 'S' ;SET STOP BITS DW SBITS DB 'L' ;SET DATA WORD LENGTH DW LENGTH DB 'P' ;SET PARITY MODE DW PARTYP DB 'F' ;SET FULL DUPLEX DW FULL DB 'H' ;HALF DUPLEX DW HALF DB 'J' ;JUMP TO ADDRESS DW JUMP DB 'C' ;CAPTURE DW CAPTURE DB 'T' ;TYPE BUFFER TO CONSOLE DW TYPE DB 'W' ;WRITE CAPTURE BUFFER TO DISK DW SAVE DB 'R' ;READ AND TRANSMIT DISK FILE DW READ DB '?' ;SET TO DEBUG MODE DW DEBUG DB 0 ;END OF TABLE ;*********** OPTIONAL DISK I/O AREA ************************ ;THESE ROUTINES ALLOW YOU TO SAVE THE CONTENTS OF ;THE CAPTURE BUFFER ON THE DISK. IF YOU DON'T HAVE ;THE CP/M DISK OPERATING SYSTEM THEY WON'T WORK. ;DISK I/O ROUTINES DELETE: LXI D,FCB MVI C,19 JMP BDOS MAKE: LXI D,FCB MVI C,22 JMP BDOS SETDMA: PUSH H MVI C,26 CALL BDOS POP H RET WRITENR: PUSH H LXI D,FCB MVI C,21 CALL BDOS POP H RET READNR: PUSH H LXI D,FCB MVI C,20 CALL BDOS POP H RET CLOSE: LXI D,FCB MVI C,16 JMP BDOS OPEN: LXI D,FCB MVI C,15 JMP BDOS ;GET NAME OF FILE FROM CONSOLE BUFFER TO FILE CONTTROL BLOCK GETNAME: CALL NXTCHR ;SET BUFFER POINTER TO FILE NAME ORA A ;TEST FOR NO FILE NAME RZ ;RETURN IF NONE ENTERED LXI H,ET ;POINT TO ENTRY TYPE XRA A ;ZERO A MVI B,12 ;LOAD COPUTER G1: MOV M,A ;FILL FCB AREA WITH 0 + 11 SPACES MVI A,20H ;A SPACE INX H ;BUMP POINTER DCR B ;COUNT'EM JNZ G1 MVI B,8 ;MAX OF 8 CHARS. IN FILE NAME LXI D,FNAME ;POINT TO FCB FILE NAME AREA CALL MVNAM ;MOVE NAME FROM BUFFER TO FCB CPI '.' JNZ G2 ;IF NO PERIOD THEN NO FILE TYPE LXI D,FTYPE ;POINT TO FILE TYPE AREA MVI B,3 ;MAX OF 3 CHARS. IN FILE TYPE CALL MVNAM ;MOVE TYPE INTO FCB AREA G2: LXI H,EX ;FILL REST OF FCB WITH ZEROS MVI B,(NR+1)-EX ;COUNTER GG3: MVI M,0 INX H DCR B JNZ GG3 LXI D,80H ;SET DMA ADDRESS TO 80H CALL SETDMA RET ;MOVES STRINGS FROM CONSOLE BUFFER TO FCB AREA ;DE POINT TO DESTINATION ;B HAS NUMBER OF CHARACTERS TO MOVE MVNAM: CALL NEXT ;GET NEXT CHARACTER CPI '.' ;END OF FILE NAME? RZ CPI CR ;END OF LINE? RZ CPI 0 ;DELIMITER? RZ STAX D ;PUT CAHRACTER IN FCB INX D ;ADVANCE POINTER DCR B JNZ MVNAM ;LOOP IF MORE CHARACTERS JMP NEXT ;GET NEXT CHARACTER AND RETURN LXI H,EX ;POINT TO EXTENT AREA OF FCB MVI B,(NR+1)-EX G3: MVI M,0 ;FILL REST OF FCB WITH ZERO INX H DCR B JNZ G3 LXI D,80H CALL SETDMA RET ;DISK FILE TRANSMIT ROUTINE READ: CALL GETNAME ;GET FILE NAME CALL OPEN CPI 255 ;OK? JNZ R1 ;JUMP IF OPEN IS OK CALL PRINT DB 'NOT FOUND',CR RET R1: CALL READNR ;READ 128 BYTES INTO 80H BUFFER CALL TXBUF ;TRANSMIT THE BUFFER CONTENTS CPI 1AH ;CONTROL Z (END OF FILE) JNZ R1 CALL CLOSE RET ;TRANSMITS THE CONTENTS OF THE DISK BUFFER TXBUF: LXI H,80H MVI B,128 TXB1: MOV C,M ;GET A CHARACTER CALL XMIT ;TRANSMIT IT MOV A,C CPI 1AH ;END OF FILE? RZ ;YES RETURN CPI CR ;END OF LINE? CZ WTRPLY ;WAIT FOR POSSIBLE PROMPT CALL RXSTAT ;SEE IF CHAR. HAS BEEN RECEIVED ORA A CNZ CRECV ;GET IT AND SEND TO CONSOLE CALL CDSTAT ;CHECK FOR CARRIER ORA A JZ ABRT ;ABORT IF NO CARRIER CALL CONST ;WANT TO ABORT? ORA A JZ TXB2 ;JUMP IF NOT CALL CONIN ;ABORT ON ANY KEY PRESSED ABRT: MVI A,1AH ;FAKE OUT THE CALLING ROUTINE RET TXB2: INX H ;BUMP BUFFER POINTER DCR B ;COUNT BYTES JNZ TXB1 RET ;THIS ROUTINE WAITS FOR 150 MS AFTER THE LAST ;CHARACTER IS RECEIVED BY THE MODEM. WTRPLY: PUSH B CALL RXSTAT ORA A CNZ RXCHR ;FLUSH UART WTRP1: MVI B,3 ;150 MS WTRP2: CALL STIME ;START TIMER WTRP3: CALL RXSTAT ;MODEM CHAR. RECEIVED? ORA A PUSH PSW ;SAVE STATUS CNZ CRECV ;GET AND SEND TO CONSOLE POP PSW ;POP FLAGS AGAIN JNZ WTRP1 ;IF CHARACTER REC. LOOP BACK CALL CKTIME ;TIME UP? ORA A JZ WTRP3 ;NO, LOOP BACK DCR B ;COUNT LOOPS JNZ WTRP2 ;LOOP IF NOT 150 MS POP B ;RESTORE BC RET ;THIS ROUTINE STORES THE CONTENTS OF THE CAPTURE ;BUFFER ON THE DISK. SAVE: CALL GETNAME CALL DELETE ;ERASE OLD FILE OF SAME NAME CALL MAKE ;MAKE NEW FILE CPI 255 JNZ S1 CALL PRINT DB 'NO DIRECTORY SPACE',CR RET S1: CALL OPEN LHLD CBUFP ;CAPTURE BUFFER POINTER XCHG ;POINTER TO DE LHLD CPCNT ;BUFFER CAHRACTER COUNT S2: MVI A,1AH ;END OF FILE MARKER STAX D INX D INX H ;FILL OUT WITH 1A'S TILL MOV A,L ;EVEN WITH 128 BYTE BOUNDRY ANI 7FH JNZ S2 DAD H ;SHIFT HL LEFT 1 BIT ACI 0 ;SHIFT CARRY INTO REG. A MOV B,A ;MSB OF RECORD COUNT TO B MOV C,H ;LSB OF RECORD COUNT IN C INX B ;ADD 1 MORE LXI D,CPBUF ;CAPTURE BUFFER START ADDRESS S3: PUSH B ;SAVE RECORD COUNT PUSH D ;SAVE BUFFER POINTER CALL SETDMA ;DMA=BUFFER CALL WRITENR ;WRITE A RECORD TO DISK ORA A ;CHECK FOR ERROR JNZ ERRR POP D ;GET CAPTURE BUFFER POINTER LXI H,128 DAD D ;ADVANCE IT 128 BYTES XCHG POP B ;GET RECORD COUNT DCX B ;COUNT 1 MOV A,B ORA C ;TEST FOR ZERO JNZ S3 ;IF NOT ZERO, LOOP BACK LXI D,80H ;RESET DMA TO 80H CALL SETDMA CALL CLOSE CPI 255 JNZ RSBUF ;CLEAR CAPTURE BUFFER CALL PRINT DB 'CANNOT CLOSE FILE',CR RET ERRR: POP H POP H ;CLEAN UP STACK CALL PRINT DB 'OUT OF SPACE',CR RET ;******* CONSOLE I/O AREA FOR CP/M ****************** ;CONSOLE INPUT ;IT RETURNS THE CHARACTER IN REGISTER A CONIN: PUSH H PUSH D PUSH B CALL XCONIN ANI 7FH ;KILL MSB POP B POP D POP H RET ;CONSOLE STATUS CHECK ;RETURNS WITH A=0 IF NO CHARACTER TYPED ;OR A=1 IF CHARACTER HAS BEEN TYPED (OR A= NOT ZERO) CONST: PUSH H PUSH D PUSH B CALL XCONST POP B POP D POP H RET ;CONSOLE OUTPUT. CHARACTER TO BE PRINTED MUST BE IN ; REG. C CONOUT: PUSH H PUSH D PUSH B CALL XCONOT POP B POP D POP H RET ;INITIALIZATION ROUTINE FOR USER HARDWARE AND SOFTWARE. ;PUT YOUR OWN SPECIAL INITIALIZATION ROUTINES HERE. ;THIS ROUTINE MOVES THE CP/M CBIOS JUMP TABLE TO ;"JTAB" IN RAM. INIT: LHLD 1 ;GET ADDRESS OF CBIOS LXI D,JTAB ;DESTINATION ADDRESS MVI B,4*3 ;NO. OF BYTES TO MOVE MOVE: MOV A,M ;GET A BYTE STAX D ;MOVE IT INX H ;ADVANCE POINTERS INX D DCR B JNZ MOVE ;COUNT BYTES MVI A,1 ;SPECIAL HARDWARE STUFF OUT 84H RET PAGE ;PRINTER TOP OF FORM ;********* MODEM I/O AREA *********** ; ALL MODEM I/O AND CONTROL ARE HERE. DLYVAL EQU 2083*MHZ ; MODEM I/O SYSTEM 5-10-79 ; WRITTEN BY DALE A. HEATHERINGTON ; COPYRIGHT 1979 D.C. HAYES ASSOCIATES, INC. ; PORT EQUATES DATA EQU 0C0H STATUS EQU DATA+1 CR1 EQU DATA+1 CR2 EQU DATA+2 CR3 EQU DATA+3 ; BIT FUNCTIONS ;STATUS REGISTER RRF EQU 1 ;RECEIVE REGISTER FULL TRE EQU 2 ;TRANSMITER HOLDING REGISTER EMPTY PE EQU 4 ;PARITY ERROR FE EQU 8 ;FRAMMING ERROR OE EQU 10H ;OVERRUN ERROR TMR EQU 20H ;TIMER STATUS CD EQU 40H ;CARRIER PRESENT RI EQU 80H ;NOT RING INDICATOR (LOW TRUE) ;CONTROL REGISTER 1 (CR1) EPE EQU 1 ;EVEN PARITY ENABLE LS1 EQU 2 ;WORD LENGTH SELECT BIT 1 LS2 EQU 4 ;WORD LENGTH SELECT BIT 2 SBS EQU 8 ;STOP BITS PI EQU 10H ;PARITY INHIBIT TMIE EQU 20H ;TIMER INTERUPTS ENABLE ;CONTROL REGISTER 2 (CR2) BRS EQU 1 ;BAUD RATE CONTROL TXE EQU 2 ;TRANSMIT CARRIER ENABLE MS EQU 4 ;MODE (0=ANSWER 1=ORIGINATE) BRK EQU 8 ;SEND BREAK ST EQU 10H ;SELF TEST TIE EQU 20H ;TRANSMITTER INTERUPT ENABLE RIE EQU 40H ;RECEIVER INTERUPT ENABLE OH EQU 80H ;OFF-HOOK ;CONTROL REGISTER 3 (CR3) ;WRITING ANYTHING TO CR3 STARTS THE 50 MS TIMER. ;THIS ROUTINE CLEARS ALL THE CONTROL REGISTERS RESET: XRA A ;ZERO A OUT CR1 OUT CR2 STA MICR2 ;CLEAR MEMORY IMAGES TOO STA MICR1 RET ;THIS ROUTINE SENDS A BYTE IN REGISTER C TO THE MODEM ;TRANSMITTER. ONLY REGISTER A IS DISTURBED TXCHR: IN STATUS ;GET MODEM STATUS ANI TXE ;CHECK FOR TRANSMITER EMPTY JZ TXCHR ;LOOP IF NOT MOV A,C OUT DATA ;SEND THE BYTE RET ;GETS A BYTE FROM THE MODEM RECEIVER IN REGISTER A RXCHR: IN STATUS ANI RRF JZ RXCHR ;LOOP IF NO CHARACTER REC. IN DATA RET ;CHARACTER IN A ;THIS ROUTINE RETURNS WITH A=1 IF A RECEIVED ;CHARACTER IS WAITING OR A=0 IF NOT. RXSTAT: IN STATUS ;GET MODEM STATUS ANI RRF ;CHECK RECEIVER FLAG RET ;A=1 IF CHARACTER PRESENT ;CARRIER STATUS CHECK. A=1 IF CARRIER IS PRESENT CDSTAT: IN STATUS ANI CD ;TEST CARRIER DETECT FLAG MVI A,0 ;ASSUME 0 RZ INR A ;MAKE A=1 IF CARRIER PRESENT RET ;RING INDICATOR STATUS CHECK. A=1 IF PHONE RINGING RISTAT: IN STATUS ANI RI MVI A,1 ;ASSUME RINGING RZ ;RETURN IF IT IS (LOW TRUE BIT) DCR A ;ELSE MAKE A=0 RET ;GET THE ERROR FLAGS. ERROR BITS ARE RETURNED IN REG. A. ;A=0 IF NO ERRORS WERE DETECTED ON LAST CHARACTER RECEIVED. ;BIT 0=PARITY ERROR BIT 1=FRAMMING ERROR ;BIT 2=OVERRUN ERROR ERFLG: IN STATUS RAR ;SHIFT BITS RIGHT 2 PLACES RAR ANI 7 ;KILL UNWANTED BITS RET ;LOW 3 BITS ARE ERROR FLAGS ;TRANSMIT CARRIER CONTROL. ;ENTER WITH REG. C=0 FOR CARRIER OFF ; OR REG. C=1 FOR TRANSMIT CARRIER ON TXON: MOV A,C ORA A MVI A,TXE ;PUT TXE BIT IN A JZ CLR2 ;CLEAR IT IF 0 JMP SET2 ;SET IT IF A 1 ;SET THE BAUD RATE. C=0 FOR LOW BAUD RATE (110) ; C=1 FOR HIGH BAUD RATE (300) BAUD: MOV A,C ORA A MVI A,BRS ;BAUD RATE BIT IN A JZ CLR2 ;RESET BIT IF 0 JMP SET2 ;SET IF 1 ;GO ON/OFF HOOK. C=0 FOR ON-HOOK (IDLE) ; C=1 FOR OFF-HOOK. SWHOOK: MOV A,C ORA A MVI A,OH ;SWITCH-HOOK BIT JZ CLR2 JMP SET2 ;GET SWITCH HOOK STATUS. ; A=0 ON HOOK A=1 OFF HOOK SHSTAT: LDA MICR2 ;GET CR2 ANI OH ;MASK FOR OFF HOOK MVI A,1 RNZ ;RET. IF OFF HOOK A=1 DCR A RET ;ELSE A=0 ;SET THE MODE. C=0 FOR ANSWER MODE ; C=1 FOR ORGINATE MODE MODE: MOV A,C ORA A MVI A,MS ;MODE SELECT BIT JZ CLR2 JMP SET2 ;SET OR CLEAR SELF-TEST MODE. ;C=1 FOR SELF TEST C=0 FOR NORMAL SELFT: MOV A,C ORA A MVI A,ST ;SELF-TEST BIT JZ CLR2 ;CLEAR IT JMP SET2 ;OR SET IT ;SEND A BREAK CONSISTING OF SENDING A SPACE (LOW TONE) FOR ; A NUMBER OF 50 MS INTERVALS SPECIFIED IN THE REG. C. BREAK: PUSH B ;SAVE BREAK DURATION VALUE MVI C,2 CALL DELAY ;WAIT 100 MS POP B ;RESTORE BREAK DURATION VALUE PUSH H LXI H,MICR2 MVI A,BRK ;SET THE BREAK BIT ORA M OUT CR2 CALL DELAY ;C=50 MS INTERVALS TO WAIT MVI A,BRK CMA ANA M ;CLEAR BREAK BIT OUT CR2 ;WRITE IT TO MODEM POP H RET ;SETS THE PARITY. C=0 FOR NO PARITY ; C=1 FOR ODD PARITY C=2 FOR EVEN PARITY PARITY: MOV A,C ORA A ;TEST FOR NO PARITY JZ PAROFF MVI A,PI CALL CLR1 ;CLEAR PARITY INHIBIT BIT MOV A,C RAR ;LSB IS NOW EVEN/ODD PARITY ANI 1 MVI A,EPE JZ CLR1 ;CLEAR EPE IF ODD JMP SET1 ;SET EPE IF EVEN PAROFF: MVI A,PI JMP SET1 ;INHIBIT PARITY ;SELECT WORD LENGTH. ;C=NUMBER OF DATA BITS (5,6,7,8) WLS: MOV A,C SUI 5 ;REMOVE BIAS ADD A ;SHIFT LEFT 1 PLACE ANI 6 ;KILL ANY STRAY BITS MOV C,A ;SAVE RESULT IN C LDA MICR1 ;GET MEMORY IMAGE ANI NOT LS1+LS2 ;CLEAR WORD LENGTH BITS ORA C ;PUT IN NEW ONES STA MICR1 ;UPDATE MEMORY OUT CR1 ;WRITE TO MODEM RET ;SET NUMBER OF STOP BITS ;C=STOP BITS (1 OR 2) NSTOP: MOV A,C SUI 1 MVI A,SBS ;STOP BIT SELECT BIT JZ CLR1 ;CLEAR IT JMP SET1 ;ELSE SET IT ;DELAY ROUTINE. ;WAITS 50 MS TIMES THE VALUE IN REGISTER C. IF MM100 ;ASSEMBLE FOR MICROMODEM 100 DELAY: MOV A,C ORA A RZ ;WAIT ZERO TIME IF C=0 PUSH B ;SAVE CONTENTS OF C DLY1: OUT CR3 ;START TIMER DLY2: IN STATUS ;WAIT TILL IT TIMES OUT ANI TMR ;LOOK AT TIMER BIT JZ DLY2 ;LOOP BACK IF ZERO DCR C ;COUNT DOWN JNZ DLY1 ;DO AGAIN IF NOT ZERO POP B RET ;STARTS THE 50 MS TIMER STIME: OUT CR3 ;START TIMER RET ;CHECKS THE STATUS OF THE TIMER. ; RETURNS WITH A=1 IF TIMED OUT OR A=0 IF NOT. CKTIME: IN STATUS ANI TMR ;MASK IN TIMER BIT MVI A,1 RNZ ;RET. A=1 IF TIMED OUT DCR A RET ;RET. A=0 IF TIME NOT UP ELSE ;ASSEMBLE FOR 80-103A DELAY: MOV A,C ORA A RZ ;WAIT ZERO TIME IF C=0 PUSH B PUSH H DLY1: LXI H,DLYVAL ;LOAD COUNTER FOR 50 MS DELAY DLY2: DCX H ;COUNT DOWN MOV A,H ORA L ;TEST FOR HL = 0 JNZ DLY2 ;LOOP TILL HL = ZERO DCR C ;COUNT 50 MS PERIODS JNZ DLY1 POP H POP B RET ;FINISHED STIME: RET ;80-103 HAS NO TIMER TO START. SORRY CKTIME: MVI A,1 ;ALWAYS TIMED OUT WITH 80-103 ENDIF ;END OF CONDITIONAL ASSEMBLY ;GOES OFF-HOOK AND WAITS FOR A DIAL TONE. SINCE THE ;MICROMODEM HAS NO DIAL TONE DETECTOR WE JUST GO ;OFF-HOOK, WAIT 2 SECONDS, ASSUME A DIAL TONE IS ;PRESENT, THEN RETURN. DLTONE: PUSH B MVI C,1 CALL SWHOOK ;GO OFF-HOOK MVI C,40 ;40*50MS=2 SECONDS CALL DELAY ;WAIT 2 SECONDS POP B ;RESTORE BC RET ;DIAL PULSE ROUTINE. DIALS THE DIGIT IN REGISTER C. ;IF C=0 THEN 10 PULSES WILL BE PRODUCED. THE DIGIT IN ;THE C REGISTER CAN BE BINARY OR ASCII. AFTER THE ;DIGIT IS OUT-PULSED THIS ROUTINE WILL PAUSE FOR 600 MS ;FOR INTER-DIGIT SPACING. PULSE: PUSH B ;SAVE BC MOV A,C MVI B,10 ;PRE-LOAD PULSE COUNTER ANI 0FH ;KILL POSSIBLE ASCII BIAS CPI 0 ;SEE IF WE'RE DOING 10 PULSES JZ PULS1 MOV B,A ;PULSE COUNT TO B PULS1: MVI C,0 ;GO ON HOOK CALL SWHOOK MVI C,1 CALL DELAY ;WAIT 50 MS MVI C,1 CALL SWHOOK ;OFF HOOK AGAIN MVI C,1 CALL DELAY ;WAIT 50 MS DCR B ;WE MADE 1 PULSE, COUNT IT JNZ PULS1 ;IF NOT ZERO, MAKE SOME MORE MVI C,11 ;11*50 MS=550 MS CALL DELAY ;INTER-DIGIT DELAY POP B ;RESTORE BC REGISTERS RET ;SETS BITS IN CONTROL REGISTER 2. ;ENTER WITH REG. A CONTAINING 1'S WHERE BITS ARE TO BE ;SET. SET2: PUSH H ;SAVE HL LXI H,MICR2 ORA M ;OR IN BITS TO BE SET MOV M,A OUT CR2 ;SET THE MODEM POP H RET ;CLEAR BITS IN CONTROL REGISTER 2. ;REG. A HAS 1'S FOR BITS TO BE CLEARED. CLR2: PUSH H LXI H,MICR2 ;MEMORY IMAGE OF CR2 CMA ANA M ;TURN OFF THE BIT MOV M,A ;UPDATE MEMORY OUT CR2 ;WRITE TO CRL. REG. 2 POP H ;RESTORE HL RET ;SET BITS IN CONTROL REGISTER 1. ;REG. A HAS 1'S IN BITS TO BE SET. SET1: PUSH H LXI H,MICR1 ;POINT TO MEMORY IMAGE ORA M ;OR IN THE BITS MOV M,A ;UPDATE MEMORY OUT CR1 ;WRITE TO MODEM POP H RET ;CLEAR BITS IN CONTROL REGISTER 1 ;REG. A HAS 1'S IN BITS TO BE CLEARED. CLR1: PUSH H LXI H,MICR1 ;POINT TO MEMORY IMAGE CMA ;INVERT A ANA M ;CLEAR BITS MOV M,A ;UPDATE MEMORY OUT CR1 POP H RET ;THIS AREA MUST BE R/W MEMORY. ORG 1000H ;RAM MEMORY AREA SOR: ;START OF RAM MICR1: DS 1 ;MEMORY IMAGE OF CONTROL REG. 1 MICR2: DS 1 ;MEMORY IMAGE OF CONTROL REG. 2 DPLX: DS 1 ;FULL DUPLEX FLAG 1=FULL 0=HALF MFLAG: DS 1 ;0=ANSWER 1=ORIGINATE JTAB: DS 3 ;CBIOS JUMP TABLE IS MOVED HERE XCONST: DS 3 ;CONSOLE STATUS XCONIN: DS 3 ;CONSOLE INPUT XCONOT: DS 3 ;CONSOLE OUTPUT NMBR: DS 32 ;32 BYTES PHONE NUMBER STORAGE BUFPNT: DS 2 ;BUFFER POINTER STORAGE CPFLAG: DS 1 ;CAPTURE FLAG 1=ON 0=OFF BUGFLAG:DS 1 ;1=DEBUG MODE 0= NORMAL BUGCOUNT: DS 1 ;COUNTS HEX BYTES PER LINE MTOP: DS 1 ;TOP OF MEMORY (PAGE) CBUFP: DS 2 ;CAPTURE BUFFER POINTER CPCNT: DS 2 ;CAPTURED CHARACTER COUNTER EOR: ;END OF RAM CHECKED BY CHECKSUM CKSUM: DS 1 ;CHECKSUM STORED HERE DS 64 STACK: DS 1 ;64 BYTES FOR STACK BUF: DS 65 ;CONSOLE BUFFER ;CPM FILE CONTROL BLOCK FCB: ET: DS 1 ;ENTRY TYPE FNAME: DS 8 ;FILE NAME FTYPE: DS 3 ;FILE TYPE EX: DS 3 ;EXTENT RCC: DS 1 ;RECORD COUNT DM: DS 16 ;DISK MAP NR: DS 1 ;NEXT RECORD CPBUF: DS 1 ;CAPTURE BUFFER END START ;THATS ALL