; VER. 1.1 5-18-79 ORG 100H CPM EQU 1 ; SET FFOR CPM ASSEMBLY BDOS EQU 5 ; CPM ENTRY REBOOT EQU 0 ; CPM WARM BOOT ; CR EQU 0DH ; CARRIAGE 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 INIITIALIZATION CALL CKRAM ; GET CHECKSUM OF RAM AREA MOV C,A LDA CKSUM ; GEEET 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 DB 'MICROMODEM 100 TERMINAL PROGRAM VEER. 1.1',CR 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 COMMAND 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 POINTER 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 THEEM 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 ; CARRIAGE 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 CONVEERT TO UPPER RET ; ; THIS ROUTINE GETS 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 ; CARRIAGE 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 ITS 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 BIAS 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 CARRIAGE RETURN-LINE FEED TO CONSOLE ; CRLF CALL PRINT DB CR RET ; ; PRINTS A STRING POINTED TO BY CONTENTS OF TOP ; OF STACK. CARRIAGE 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 ; GEET 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 CR? JNZ PRN1 ; NO, GO BACK FOR MORE CALL PRINT ; CALL OURSELF DB LF,0,0,0,'@' ; LF 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" COMMANDD THE ; LAST NUMBER DIALED WILL BE REDIALED. ; 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. BUFFEER 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 THEM 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. CHARACTERS 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 ; XMIT 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 'BADD 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 CAPTUREE 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. ; THEE 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 SPECIFIED 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. CARRIAGE RETURN ABORTS ; THIS FUNCTION. ; TYPE CALL GETHEX LXI H,CPBUF ; STARTING ADDRESS OF BUFFER DAD D ; ADDD 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 CALL 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 XMIT 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 CONTROL 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 CHAR. 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 D,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 CHARACTER 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 XMIT 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 ; XMIT THE BUFFER CONTENTS CPI 1AH ; CONTROL Z (END OF FILE) JNZ R1 CALL CLOSE RET ; ; TRANSMITTS THE CONTENTS OF THE DISK BUFFER ; TXBUF LXI H,80H MVI A,128 TXB1 MOV C,M ; GET A CHARACTER CALL XMIT ; XMIT 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 ANDD 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 M S AFTEER THE LAST ; CHARACTER IS RECEIVED BY THE M ODEM. ; 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 ; TIMES 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 CHARACTER COUNT S2 MVI A,1AH ; ENDD 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 RECORDDD 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 CAPTUREE 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 REG. A ; CONIN PUSH H PUSH D PUSH B CALL XCONIN ANI 7FH ; KILL MSB POP B POP D POP H RET ;; ; CONSOLE STATUS CHECK ; REETURNS WITH A=0 IF NO CHARACTER TYPED ; OR A=1 IF CHARACTER HAS BEEEN 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 ANDD CONTROL ARE HERE. ; MODEM I/O SYSTEM 5-10-79 ; ; PORT EQUATES FOR D.C. HAYES ; DATA EQU 80H 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 ; XMIT 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 ; XMIT CARRIER ENABLE MS EQU 4 ; MODE (0=ANSWER, 1=ORIGINATE) BRK EQU 8 ; SEND BREAK ST EQU 10H ; SELF TEST TIE EQU 20H ; XMIT INTERUPT ENABLE RIE EQU 40H ; RECEIVER INTRUPT 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 XMITER EMPTY JZ TXCHR ; LOOP IF NOT MOV A,C OUT DATA ; SEND IT 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 RECEIVEER 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 ; BITT 2=OVERRUN ERROR ; ERFLG IN STATUS RAR!RAR! ; SHIFT BITS RIGHT 2 PLACES ANI 7 ; KILL UNWANTED BITS RET ; LOW 3 BITS ARE ERROR FLAGS ; ; TRANSMIT CARRIER CONTROL ; ENTER WITH REEG. C=0 FOR CARRIER OFF ; OR REG. C=1 FOR XMIT 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 FFOR 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 ; RETURN IF OFF HOOK A=1 DCR A RET ; ELSE A=0 ; ; SET THE MODE. C=0 FOR ANSWEER MODE ; C=1 FOR ORIGINATE 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 A 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=11 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 NO 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. ; 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 N OT UP ; ; 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 IN B PULS1 MVI C,0 ; GO ON HOOK CALL SWHOOK MVI C,1 CALL DELAY ; WAIT 50 MS MVI C,1 CALL DELAY ; WAIT 50 MS DCR B ; WE MADDE 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 RET ; ; SETS BITS IN CONTROL REGISTER 2. ; ENTER WITH REG. A CONTAINING 1'S WHERE BITS ARE TO BE ; SET. ; SET2 PUSH H 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 RET ; ; SET BITS IN CONTROL REGISTER 1 ; REG A HAS 1'S IN BITS TO BE SET ; SET1 PUSH H LXI H,MICR1 ORA M MOV M,A OUT CR1 POP H RET ; ; CLEAR BITS IN CONTROL REG 1 ; REG A HAS 1'S IN BITS TO BE CLEARED ; CLR1 PUSH H LXI H,MICR1 CMA ANA M MOV M,A 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 DUPLES FLAG 1=FULL, 0=HALF MFLAG DS 1 ; O=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 ; ENDD 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 FOLKS