; VER. 1.1 5-18-79 0100 ORG 100H 0001 = CPM EQU 1 ; SET FFOR CPM ASSEMBLY 0005 = BDOS EQU 5 ; CPM ENTRY 0000 = REBOOT EQU 0 ; CPM WARM BOOT ; 000D = CR EQU 0DH ; CARRIAGE RETURN 000A = LF EQU 0AH ; LINE FEED 0007 = BELL EQU 7 ; ASCII BELL ; 0100 317B10 START LXI SP,STACK 0103 CDBD09 CALL INIT ; SET UP CP/M I/O VECTORS 0106 11AE01 LXI D,PROMPT ; PUSH A RETURN ADDRESS ON STACK 0109 D5 PUSH D ; IN CASE CARRIER IS PRESENT 010A CDF809 CALL CDSTAT ; SEE IF WE GOT CARRIER 010D B7 ORA A 010E CA4501 JZ STR1 ; NO, DO INIITIALIZATION 0111 CDC801 CALL CKRAM ; GET CHECKSUM OF RAM AREA 0114 4F MOV C,A 0115 3A3A10 LDA CKSUM ; GEEET OLD CHECKSUM 0118 B9 CMP C ; SAME? 0119 CA9104 JZ TALK ; RAM OK, JUMP TO COMM LOOP 011C CDDF02 CALL PRINT 011F 5245454E54 DB 'REENTRY NOT POSSIBLE. RAM OVERWRITTEN',CR 0145 CDD209 STR1 CALL RESET ; ELSE CLEAR MODEM 0148 3A0700 LDA 7 ; GET PAGE ADDRESS OF CP/M 014B D601 SUI 1 ; 1 PAGE BELOW IT 014D 323510 STA MTOP ; TOP OF USER MEMORY 0150 CDDA02 CALL CRLF 0153 CDDF02 CALL PRINT 0156 09442E432E DB ' D.C. HAYES ASSOCIATES, INC.',CR 0173 CDDF02 CALL PRINT 0176 4D4943524F DB 'MICROMODEM 100 TERMINAL PROGRAM VEER. 1.1',CR 01A0 AF XRA A ; A=0 01A1 321010 STA NMBR ; SET PHONE NUMBER BUFFER EMPTY 01A4 21B401 LXI H,DFAULT ; POINT TO COMMAND STRING 01A7 223010 SHLD BUFPNT ; OF DEFAULT OPTIONS 01AA CDF001 CALL DEC1 ; EXECUTE THE COMMAND 01AD D1 POP D ; CLEAN UP STACK ; 01AE CDD601 PROMPT CALL CMND ; GET AND EXECUTE COMMANDS 01B1 C3AE01 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. ; 01B4 4C382C5331DFAULT DB 'L8,S1,PN,B3,F,C0,?0',CR ; DOES A CHECKSUM OF THE SCRATCH PAD RAM LOCATIONS ; 01C8 063A CKRAM MVI B,EOR-SOR ; END OF RAM MINUS START OF RAM=COUNT 01CA 210010 LXI H,SOR ; START OF RAM POINTER 01CD 3E00 MVI A,0 ; A IS CHECKSUM 01CF 86 CKR1 ADD M ; ADD MEMORY BYTE 01D0 23 INX H ; INC POINTER 01D1 05 DCR B ; COUNT 'EM 01D2 C2CF01 JNZ CKR1 ; LOOP IF NOT DONE 01D5 C9 RET ; CHECKSUM IN REG A ; ; THIS ROUTINE FILLS THE COMMAND BUFFER WITH ; A COMMAND STRING FROM THE CONSOLE THEN ; DECODES AND EXECUTES THEM. ; 01D6 CDDA02 CMND CALL CRLF 01D9 CDDF02 CALL PRINT 01DC 434F4D4D41 DB 'COMMAND:@' 01E5 CD2A02 CALL FILBUF ; GET COMMANDS TO BUFFER 01E8 B7 ORA A ; TEST FOR NO COMMANDS 01E9 C8 RZ ; RETURN IF NONE IN BUFFER ; 01EA 217C10 DECODE LXI H,BUF ; POINT TO COMMAND BUFFER 01ED 223010 SHLD BUFPNT ; SAVE POINTER 01F0 CD7E02 DEC1 CALL NEXT ; GET A COMMAND 01F3 FE0D CPI CR ; END OF LINE? 01F5 C8 RZ 01F6 B7 ORA A ; DELIMITER? 01F7 CAF001 JZ DEC1 01FA 21B707 LXI H,TABLE ; POINT TO DECODE TABLE 01FD 4F MOV C,A ; STORE COMMAND IN C 01FE 7E SRCH MOV A,M ; GET BYTE FROM TABLE 01FF B9 CMP C ; DOES IT MATCH? 0200 CA2002 JZ FOUND ; YES, JUMP 0203 23 INX H ; NO, ADVANCE POINTER 0204 23 INX H 0205 23 INX H 0206 B7 ORA A ; TEST FOR END OF TABLE 0207 C2FE01 JNZ SRCH 020A CDB309 CALL CONOUT ; ECHO BAD COMMAND 020D CDDF02 CALL PRINT 0210 203D204241 DB ' = BAD COMMAND',CR 021F C9 RET ; 0220 11F001 FOUND LXI D,DEC1 ; RETURN ADDRESS 0223 D5 PUSH D ; PUT IT ON STACK 0224 23 INX H 0225 5E MOV E,M ; GET LOW BYTE OF COMMAND ADR. 0226 23 INX H 0227 56 MOV D,M ; GET HIGH BYTE 0228 EB XCHG ; ADDRESS TO HL 0229 E9 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. ;; 022A 217C10 FILBUF LXI H,BUF 022D 0600 MVI B,0 ; CHARACTER COUNTER 022F CD9D09 FIL1 CALL CONIN ; GET ONE 0232 FE7F CPI 7FH ; IS IT A RUBOUT? 0234 C24602 FIL2 JNZ FIL3 ; JUMP IF NOT 0237 78 MOV A,B 0238 B7 ORA A ; SEE IF BUFFER EMPTY 0239 CA2A02 JZ FILBUF 023C 2B DCX H 023D 05 DCR B ; BACK UP EVERYTHING 023E 0E5F MVI C,5FH ; BACK ARROW CHARACTER 0240 CDB309 CALL CONOUT 0243 C32F02 JMP FIL1 0246 FE15 FIL3 CPI 15H ; CONTROL U? 0248 C25502 JNZ FIL4 024B 0E23 MVI C,'#' 024D CDB309 CALL CONOUT ; ECHO # 0250 CDDA02 CALL CRLF 0253 AF XRA A 0254 C9 RET ; RETURN A=0 0255 FE0D FIL4 CPI CR ; CARRIAGE RETURN 0257 C26002 JNZ FIL5 025A 77 MOV M,A ; PUT IT IN BUFFER 025B 78 MOV A,B ; GET COUNT 025C CDDA02 CALL CRLF 025F C9 RET 0260 CD7802 FIL5 CALL UCASE ; CONVERT TO UPPER CASE 0263 77 MOV M,A ; PUT IT IN MEMORY 0264 4F MOV C,A 0265 3E40 MVI A,64 ; MAX. LENGTH OF BUFFER 0267 B8 CMP B 0268 C27002 JNZ FIL6 ; JUMP IF NOT FULL 026B 0E23 MVI C,'#' 026D C37202 JMP FIL7 0270 23 FIL6 INX H 0271 04 INR B ; ADVANCE POINTER AND COUNTER 0272 CDB309 FIL7 CALL CONOUT ; ECHO CHARACTER 0275 C32F02 JMP FIL1 ; ; LOWER TO UPPER CASE CONVERSION ROUTINE. ; 0278 FE60 UCASE CPI 60H 027A D8 RC ; RETURN IF ALREADY UPPER CASE 027B D620 SUI 20H ; ELSE CONVEERT TO UPPER 027D C9 RET ; ; THIS ROUTINE GETS NEXT CHARACTER FROM THE BUFFER. ; IT RETURNS A=0 IF A COMMA OR SPACE IS ENCOUNTERED ; 027E 2A3010 NEXT LHLD BUFPNT ; GET ADDRESS OF BUFFER 0281 7E MOV A,M ; GET A BYTE 0282 23 INX H 0283 223010 SHLD BUFPNT ; INCREMENT AND SAVE POINTER 0286 FE20 CPI 20H ; SPACE? 0288 CA9802 JZ DELM 028B FE2C CPI ',' ; COMMA? 028D CA9802 JZ DELM 0290 FE0D CPI CR ; CARRIAGE RETURN 0292 C0 RNZ ; RETURN IF NOT 0293 2B DCX H 0294 223010 SHLD BUFPNT 0297 C9 RET 0298 AF DELM XRA A 0299 C9 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 ; 029A CD7E02 NXTCHR CALL NEXT 029D 0E00 MVI C,0 029F FE0D CPI CR ; TEST FOR END OF BUFFER 02A1 CAB002 JZ NXT1 02A4 B7 ORA A ; TEST FOR DELIMITER 02A5 CA9A02 JZ NXTCHR ; JUMP IF SPACE OR COMMA 02A8 0C INR C ; C=1 02A9 2A3010 LHLD BUFPNT ; GET BUFFER POINTER 02AC 2B DCX H ; BACK UP ONE 02AD 223010 SHLD BUFPNT ; STORE IT 02B0 79 NXT1 MOV A,C ; A=0 NONE FOUND 02B1 C9 RET ; A=1 CHARACTER FOUND ; ; GET A HEX DIGIT STRING FROM BUFFER AND ; CONVERT IT TO A 16 BIT BINARY NUMBER IN DE. ; 02B2 210000 GETHEX LXI H,0 02B5 EB GH1 XCHG ; NUMBER TO DE 02B6 CD7E02 CALL NEXT ; GET A DIGIT 02B9 FE30 CPI '0' ; SEE IF ITS HEX 02BB D8 RC ; RETURN ON FIRST NON HEX CHAR. 02BC FE47 CPI 'G' 02BE D0 RNC 02BF FE41 CPI 'A' 02C1 D2C702 JNC GH2 02C4 FE3A CPI ':' 02C6 D0 RNC 02C7 D630 GH2 SUI 30H ; REMOVE ASCII BIAS 02C9 FE0A CPI 10 02CB DAD002 JC GH3 ; JUMP IF DIGIT 0-9 02CE D607 SUI 7 ; ELSE REMOVE A-F BIAS 02D0 EB GH3 XCHG ; NUMBER TO HL 02D1 29 DAD H ; SHIFT LEFT 4 BITS 02D2 29 DAD H 02D3 29 DAD H 02D4 29 DAD H 02D5 85 ADD L ; ADD IN THIS DIGIT 02D6 6F MOV L,A 02D7 C3B502 JMP GH1 ; ; SEND CARRIAGE RETURN-LINE FEED TO CONSOLE ; 02DA CDDF02 CRLF CALL PRINT 02DD 0D DB CR 02DE C9 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. ; 02DF E3 PRINT XTHL ; TOP OF STACK TO HL 02E0 F5 PUSH PSW ; SAVE REGISTERS 02E1 C5 PUSH B 02E2 7E PRN1 MOV A,M ; GEET A CHARACTER 02E3 23 INX H 02E4 FE40 CPI '@' ; END? 02E6 CAFA02 JZ PRN2 ; JUMP IF END, NO CRLF 02E9 4F MOV C,A 02EA CDB309 CALL CONOUT ; PRINT THE CHAR. 02ED FE0D CPI CR ; WAS IT A CR? 02EF C2E202 JNZ PRN1 ; NO, GO BACK FOR MORE 02F2 CDDF02 CALL PRINT ; CALL OURSELF 02F5 0A00000040 DB LF,0,0,0,'@' ; LF AND 3 NULLS 02FA C1 PRN2 POP B ; RESTORE REGISTERS 02FB F1 POP PSW 02FC E3 XTHL ; RETURN ADDRESS TO STACK 02FD C9 RET ; ; RETURNS TO USERS OPERATING SYSTEM ; 02FE CDDA02 QUIT CALL CRLF 0301 CD2F0A CALL SHSTAT ; GET SWITCH-HOOK STATUS 0304 B7 ORA A 0305 CA0000 JZ REBOOT 0308 CDDF02 CALL PRINT 030B 444F20594F DB 'DO YOU WANT TO HANG UP FIRST? (Y OR N)@' 0332 CD9D09 CALL CONIN 0335 CD7802 CALL UCASE 0338 4F MOV C,A 0339 CDB309 CALL CONOUT 033C 79 MOV A,C 033D FE4E CPI 'N' 033F C24B03 JNZ QUIT1 0342 CDC801 CALL CKRAM ; GET CURRENT RAM CHECKSUM 0345 323A10 STA CKSUM ; SAVE IT 0348 C30000 JMP REBOOT ; BACK TO CPM 034B CD7005 QUIT1 CALL HANGUP 034E C30000 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. ; 0351 CDDF02 DIAL CALL PRINT 0354 4449414C49 DB 'DIALING-@' 035D CDC00A CALL DLTONE ; GET A DIAL TONE 0360 CD9A02 CALL NXTCHR ; FIND PHONE NO. IN BUFFER 0363 B7 ORA A 0364 CA7A03 JZ DL1 ; PHONE NUMBER NOT PRESENT 0367 110F10 LXI D,NMBR-1 ; POINT TO PHONE NO. BUFFEER 036A CD7E02 DL0 CALL NEXT ; GET A DIGIT 036D 13 INX D ; ADVANCE POINTER 036E 12 STAX D ; PUT IT IN BUFFER 036F B7 ORA A 0370 CA7A03 JZ DL1 0373 FE0D CPI CR 0375 C26A03 JNZ DL0 ; IF NOT END, LOOP BACK 0378 AF XRA A ; A=0 0379 12 STAX D ; ZERO MARKS END OF NUMBER 037A 211010 DL1 LXI H,NMBR ; POINT TO NUMBER BUFFER 037D 7E DL2 MOV A,M ; GET A DIGIT 037E 23 INX H ; ADVANCE POINTER 037F B7 ORA A ; TEST FOR END 0380 CA1A04 JZ COMM ; GO TRY TO COMMUNICATE 0383 4F MOV C,A 0384 CDB309 CALL CONOUT ; ECHO DIGIT WE'RE DIALING 0387 79 MOV A,C 0388 0E28 MVI C,40 038A FE2A CPI '*' ; 2 SECOND DELAY? 038C F5 PUSH PSW 038D CCA10A CZ DELAY ; YES, WAIT 2 SEC 0390 F1 POP PSW 0391 CA7D03 JZ DL2 0394 FE3A CPI 3AH ; IGNORE ALL XCEPT DIGITS 0396 D27D03 JNC DL2 0399 FE30 CPI '0' 039B DA7D03 JC DL2 039E 4F MOV C,A 039F CDCD0A CALL PULSE ; DIAL THE DIGIT 03A2 C37D03 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. ; 03A5 CD7E02 ANSWR CALL NEXT ; GET NEXT CHARACTER 03A8 FE41 CPI 'A' ; A=ANSWER WITHOUT A RING 03AA CAF103 JZ ANS2 ; IN ANSWER MODE 03AD FE4F CPI 'O' ; O=ANSWER WITHOUT A RING 03AF CA1A04 JZ COMM ; IN ORIGINATE MODE 03B2 CDDF02 CALL PRINT ; ELSE WAIT FOR RING 03B5 5741495449 DB 'WAITING FOR RING. PRESS ANY KEY TO ABORT.',CR 03DF CD010A ANS1 CALL RISTAT ; CHECK FOR PHONE RINGING 03E2 B7 ORA A 03E3 C2F103 JNZ ANS2 ; IF YES THEN ANSWER IT 03E6 CDA909 CALL CONST ; ABORT? 03E9 B7 ORA A 03EA CADF03 JZ ANS1 ; NO, LOOP BACK 03ED CD9D09 CALL CONIN ; GET CHARACTER 03F0 C9 RET ; ABORT 03F1 CDDF02 ANS2 CALL PRINT 03F4 07414E5357 DB BELL,'ANSWERING CALL',CR 0404 0E01 MVI C,1 0406 CD250A CALL SWHOOK ; ANSWER PHONE 0409 3E00 MVI A,0 ; A=0 FOR ANSWER MODE 040B 320310 STA MFLAG 040E 4F MOV C,A 040F CD390A CALL MODE ; SET TO ANSWER MODE 0412 0E01 MVI C,1 0414 CD110A CALL TXON ; TURN ON TRANSMIT CARRIER 0417 C32604 JMP COMM1 ; ; THIS ROUTINE WAITS FOR A CARRIER THEN GOES INTO ; THE TELETYPE MODE FOR COMMUNICATIONS. ; 041A CDDA02 COMM CALL CRLF 041D 3E01 MVI A,1 ; ORIGINATE MODE 041F 320310 STA MFLAG ; SET TO MODE 0422 4F MOV C,A 0423 CD390A CALL MODE 0426 1E1E COMM1 MVI E,30 ; SET FOR 30 SECONDS 0428 CDDF02 CALL PRINT 042B 5741495449 DB 'WAITING FOR CARRIER, PRESS ANY KEY TO ABORT.',CR 0458 0E14 CM1 MVI C,20 ; FOR 1 SECOND DELAY 045A CDA10A CALL DELAY ; WAIT A SECOND 045D CDF809 CALL CDSTAT ; LOOK FOR A CARRIER 0460 B7 ORA A ; SET FLAGS 0461 C29104 JNZ TALK 0464 CDA909 CALL CONST ; CHECK CONSOLE 0467 B7 ORA A 0468 C26F04 JNZ CM2 ; ABORT IF ANY KEY PRESSED 046B 1D DCR E ; COUNT SECONDS 046C C25804 JNZ CM1 ; LOOP 30 TIMES 046F CDDF02 CM2 CALL PRINT 0472 4E4F204341 DB 'NO CARRIER RECEIVED',BELL,CR 0487 CDA909 CALL CONST ; CHECK CONSOLE 048A B7 ORA A 048B C49D09 CNZ CONIN ; THROW AWAY CHARACTER 048E C37005 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. ;; 0491 CDF809 TALK CALL CDSTAT 0494 B7 ORA A 0495 CACC04 JZ TLK2 0498 0E01 MVI C,1 049A CD110A CALL TXON ; TURN ON CARRIER 049D CDDF02 CALL PRINT 04A0 434F4E4E45 DB 'CONNECTION ESTABLISHED',CR 04B7 CDA909 TLK1 CALL CONST ; CHECK FOR CONSOLE CHAR. 04BA B7 ORA A 04BB C4E904 CNZ CSEND ; SEND IT IF PRESENT 04BE CDF309 CALL RXSTAT ; SEE IF MODEM HAS A CHARN 04C1 B7 ORA A 04C2 C40B05 CNZ CRECV ; GET IT IF PRESENT 04C5 CDF809 CALL CDSTAT ; CHECK FOR CARRIER 04C8 B7 ORA A 04C9 C2B704 JNZ TLK1 ; IF CARRIER, CONTINUE 04CC CDDA02 TLK2 CALL CRLF 04CF CDDF02 CALL PRINT 04D2 5B2A204C4F DB '[* LOST CARRIER *]',BELL,CR 04E6 C37005 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. ;; 04E9 CD9D09 CSEND CALL CONIN ; GET CHAR. FROM CONSOLE 04EC FE01 CPI 1 ; CONTROL A? 04EE CAD601 JZ CMND ; BACK TO COMMAND MODE 04F1 0E03 MVI C,3 ; PREPARE FOR 150 MS BREAK 04F3 FE17 CPI 17H ; CONTROL W? 04F5 CA4D0A JZ BREAK ; YES, SEND BREAK 04F8 4F MOV C,A 04F9 CDDE09 XMIT CALL TXCHR ; SEND TO MODEM 04FC 3A0310 LDA MFLAG ; GET MODE 0=ANS 1=ORG 04FF B7 ORA A 0500 CAB309 JZ CONOUT ; ECHO IF ANSWER MODE 0503 3A0210 LDA DPLX ; GET DUPLEX FLAG 1=FULL 0506 B7 ORA A 0507 CAB309 JZ CONOUT ; ECHO IF HALF DUPLEX 050A C9 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. ; 050B CDE909 CRECV CALL RXCHR ; GET CHARACTER FROM MODEM 050E 4F MOV C,A 050F 3A3310 LDA BUGFLAG ; SEE IF WE PRINT IT IN HEX 0512 B7 ORA A 0513 CA2D05 JZ REC1 ; JUMP IF NOT HEX DISP. MODE 0516 CD4E05 CALL PRNHEX 0519 0E20 MVI C,20H ; ASCII SPACE 051B CDB309 CALL CONOUT ; SPACE BETWEEN HEX NUMBERS 051E 3A3410 LDA BUGCOUNT 0521 3D DCR A 0522 323410 STA BUGCOUNT 0525 E60F ANI 0FH 0527 CCDA02 CZ CRLF 052A C33E05 JMP REC2 052D CD0A0A REC1 CALL ERFLG ; GER --T ERROR FLAGS 0530 E601 ANI 1 0532 CA3705 JZ REC3 0535 0E23 MVI C,'#' ; # SUBS FOR CHAR. WITH PARITY ERROR 0537 79 REC3 MOV A,C 0538 E67F ANI 7FH ; KILL MSB 053A 4F MOV C,A 053B CDB309 CALL CONOUT ; SEND TO CONSOLE 053E CDFB06 REC2 CALL CPBFIL ; ALSO TO CAPTURE BUFFER 0541 3A0310 LDA MFLAG ; GET MODE 1=ORG 0=ANS 0544 B7 ORA A 0545 C0 RNZ ; DON'T ECHO TO LINE IF ORIG. 0546 3A0210 LDA DPLX ; GET DUPLEX FLAG 1=FULL 0549 B7 ORA A 054A C2DE09 JNZ TXCHR ; ECHO BACK TO SENDER 054D C9 RET ; ; PRINTS INCOMMING CHARACTERS IN HEX WITH THE MODEM STATUS WORD. 054E C5 PRNHEX PUSH B ; CHARACTER IS IN C, SAVE IT 054F 79 MOV A,C 0550 0F0F0F0F RRC!RRC!RRC!RRC! 0554 CD5F05 CALL PRNH1 0557 C1 POP B ; RESTORE CHARACTER 0558 C5 PUSH B ; SAVE AGAIN 0559 79 MOV A,C 055A CD5F05 CALL PRNH1 ; PRINT LOW NIBBLE 055D C1 POP B 055E C9 RET ; 055F E60F PRNH1 ANI 0FH ; KEEP LOW 4 BITS 0561 C630 ADI 30H ; ASCII BIAS ADDED 0563 4F MOV C,A 0564 FE3A CPI 3AH 0566 DAB309 JC CONOUT 0569 3E07 MVI A,7 056B 81 ADD C ; MAKE LETTER A-F 056C 4F MOV C,A 056D C3B309 JMP CONOUT ; ; THIS ROUTINE HANGS UP AND TURNS OFF THE TX CARRIER ; 0570 0E00 HANGUP MVI C,0 0572 CD110A CALL TXON ; XMIT CARRIER OFF 0575 0E00 MVI C,0 0577 CD250A CALL SWHOOK ; GO ON-HOOK 057A CDDF02 CALL PRINT 057D 5B2048554E DB '[ HUNG UP ]',BELL,CR 058A 0E14 MVI C,20 ; SET FOR 1 SECOND DELAY 058C CDA10A CALL DELAY ; WAIT FOR THINGS TO DISCONNECT 058F C9 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. ; 0590 CDB202 BRATE CALL GETHEX ; GET A DIGIT 0593 7B MOV A,E 0594 FE01 CPI 1 ; 110 BAUD? 0596 CAAF05 JZ BR110 0599 FE03 CPI 3 059B C2C005 JNZ BADBR ; BAD IF NOT 110 OR 300 059E CDDF02 CALL PRINT 05A1 3330302042 DB '300 BAUD',CR 05AA 0E01 MVI C,1 05AC C31B0A JMP BAUD ; SET RATE 05AF CDDF02 BR110 CALL PRINT 05B2 3131302042 DB '110 BAUD',CR 05BB 0E00 MVI C,0 05BD C31B0A JMP BAUD 05C0 CDDF02 BADBR CALL PRINT 05C3 4241444420 DB 'BADD BAUD RATE',CR 05D2 C9 RET ; ; LETS USER CHANGE LENGTH OF DATA WORD (5,6,7,8 BITS) ;; 05D3 CDB202 LENGTH CALL GETHEX ; GET LENGTH 05D6 CDEB05 CALL PDIGIT ; PRINT IT 05D9 CDDF02 CALL PRINT 05DC 2044415441 DB ' DATA BITS',CR 05E7 4B MOV C,E 05E8 C3830A JMP WLS ; SET MODEM BOARD 05EB 3E30 PDIGIT MVI A,30H 05ED 83 ADD E ; MAKE NUMBER IN E ASCII 05EE 4F MOV C,A 05EF CDB309 CALL CONOUT ; PRINT IT 05F2 C9 RET ; ; SET NUMBER OF STOP BITS ( 1 OR 2 ). ; 05F3 CDB202 SBITS CALL GETHEX 05F6 CDEB05 CALL PDIGIT 05F9 CDDF02 CALL PRINT 05FC 2053544F50 DB ' STOP BITS',CR 0607 4B MOV C,E 0608 C3960A JMP NSTOP ; SET THE MODEM ; ; SETS FULL DUPLEX MODE ( F COMMAND) ; 060B 3E01 FULL MVI A,1 060D 320210 STA DPLX ; SET FLAG 0610 CDDF02 CALL PRINT 0613 46554C4C20 DB 'FULL DUPLEX',CR 061F C9 RET ; ; SET HALF DUPLEX MODE ( H COMMAND) ; 0620 AF HALF XRA A 0621 320210 STA DPLX ; CLEAR FLAG 0624 CDDF02 CALL PRINT 0627 48414C4620 DB 'HALF DUPLEX',CR 0633 C9 RET ; ; SET PARITY, N=NO PARITY E=EVEN PARITY O=ODD PARITY ; 0634 CD9A02 PARTYP CALL NXTCHR ; FIND NEXT CHARACTER IN BUFF. 0637 CD7E02 CALL NEXT ; GET IT 063A FE4E CPI 'N' 063C CA4A06 JZ NPAR 063F FE45 CPI 'E' 0641 CA5C06 JZ EPAR 0644 FE4F CPI 'O' 0646 CA7006 JZ OPAR 0649 C9 RET 064A CDDF02 NPAR CALL PRINT 064D 4E4F205041 DB 'NO PARITY',CR 0657 0E00 MVI C,0 0659 C3680A JMP PARITY 065C CDDF02 EPAR CALL PRINT 065F 4556454E20 DB 'EVEN PARITY',CR 066B 0E02 MVI C,2 066D C3680A JMP PARITY 0670 CDDF02 OPAR CALL PRINT 0673 4F44442050 DB 'ODD PARITY',CR 067E 0E01 MVI C,1 0680 C3680A 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 ; 0683 CD9A02 JUMP CALL NXTCHR ; FIND ADDRESS 0686 CDB202 CALL GETHEX ; CONVERT TO BINARY IN DE 0689 EB XCHG ; ADDRESS TO HL 068A E9 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. ; 068B CD9A02 CAPTURE CALL NXTCHR ; FIND DIGIT 068E B7 ORA A 068F C8 RZ ; RETURN IF NO ARG. 0690 CD7E02 CALL NEXT ; GET DIGIT 0693 FE30 CPI '0' 0695 CAD006 JZ RSBUF ; IF ZERO, RESET 0698 FE31 CPI '1' 069A CAB706 JZ STRT ; IF 1 START CAPTURE MODE 069D FE32 CPI '2' 069F C0 RNZ ; IF 2 STOP CAPTURE 06A0 AF XRA A 06A1 323210 STA CPFLAG ; CLEAR CAPTURE FLAG 06A4 CDDF02 CALL PRINT 06A7 4341505455 DB 'CAPTURE STOPED',CR 06B6 C9 RET 06B7 3E01 STRT MVI A,1 06B9 323210 STA CPFLAG ; SET CAPTURE FLAG 06BC CDDF02 CALL PRINT 06BF 4341505455 DB 'CAPTURE ENABLED',CR 06CF C9 RET 06D0 21DE10 RSBUF LXI H,CPBUF ; START OF CAPTURE BUFFER 06D3 223610 SHLD CBUFP ; STORE POINTER 06D6 AF XRA A 06D7 323210 STA CPFLAG ; CLEAR FLAG 06DA 323810 STA CPCNT ; CLEAR BYTE COUNTER 06DD 323910 STA CPCNT+1 06E0 CDDF02 CALL PRINT 06E3 4341505455 DB 'CAPTURE BUFFER CLEARED',CR 06FA C9 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". ; 06FB 3A3210 CPBFIL LDA CPFLAG ; GET FLAG 06FE B7 ORA A 06FF C8 RZ ; RETURN IF NOT ENABLED 0700 E5 PUSH H ; SAVE HL 0701 2A3610 LHLD CBUFP ; GET BUFFER POINTER 0704 71 MOV M,C ; PUT CHARACTER IN BUFFER 0705 23 INX H ; ADVANCE POINTER 0706 3A3510 LDA MTOP ; TOP OF MEMORY 0709 BC CMP H ; CHECK FOR "OUT OF MEMORY" 070A CA1907 JZ OUTMEM 070D 223610 SHLD CBUFP ; SAVE POINTER 0710 2A3810 LHLD CPCNT ; GET CHARACTER COUNTER 0713 23 INX H ; INCREMENT IT 0714 223810 SHLD CPCNT ; STORE IT 0717 E1 POP H 0718 C9 RET 0719 CDDA02 OUTMEM CALL CRLF 071C CDDF02 CALL PRINT 071F 4341505455 DB 'CAPTURE BUFFER FULL',BELL,CR 0734 AF XRA A 0735 323210 STA CPFLAG ; DISABLE CAPTURE MODE 0738 E1 POP H 0739 C9 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. ; 073A CDB202 TYPE CALL GETHEX 073D 21DE10 LXI H,CPBUF ; STARTING ADDRESS OF BUFFER 0740 19 DAD D ; ADDD USERS COUNT TO STARTING ADR. 0741 3A3810 TY1 LDA CPCNT ; SEE IF WE'RE AT END 0744 BB CMP E 0745 C24D07 JNZ TY0 0748 3A3910 LDA CPCNT+1 074B BA CMP D 074C C8 RZ ; QUIT AT END OF BUFFER 074D 4E TY0 MOV C,M ; GET A CHARACTER 074E CDB309 CALL CONOUT ; PRINT IT 0751 CDA909 CALL CONST ; CHECK FOR CONSOLE INPUT 0754 B7 ORA A 0755 CA7507 JZ TY2 0758 CD9D09 CALL CONIN ; GET CONSOLE 075B FE0D CPI CR ; WANT TO ABORT? 075D C8 RZ ; IF YES, THEN RETURN 075E FE53 CPI 'S' ; WANT TO STOP? 0760 C27507 JNZ TY2 0763 CDA909 TY3 CALL CONST 0766 B7 ORA A 0767 CA6307 JZ TY3 ; WAIT FOR ANOTHER S 076A CD9D09 CALL CONIN 076D FE0D CPI CR 076F C8 RZ 0770 FE53 CPI 'S' 0772 C26307 JNZ TY3 0775 23 TY2 INX H ; ADVANCE POINTERS 0776 13 INX D 0777 C34107 JMP TY1 ; LOOP BACK FOR MORE 077A CD7E02 DEBUG CALL NEXT 077D FE30 CPI '0' 077F CAA007 JZ DBOFF 0782 FE31 CPI '1' ; DEBUG ON? 0784 C0 RNZ 0785 CDDF02 CALL PRINT 0788 4445425547 DB 'DEBUG MODE ON',CR 0796 3E01 MVI A,1 0798 323310 STA BUGFLAG 079B 3D DCR A 079C 323410 STA BUGCOUNT 079F C9 RET 07A0 CDDF02 DBOFF CALL PRINT 07A3 4445425547 DB 'DEBUG MODE OFF',CR 07B2 AF XRA A 07B3 323310 STA BUGFLAG 07B6 C9 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. ; 07B7 58 TABLE DB 'X' ; EXIT TO CP/M 07B8 FE02 DW QUIT 07BA 44 DB 'D' ; DIAL A NUMBER 07BB 5103 DW DIAL 07BD 41 DB 'A' ; ANSWER CALLS 07BE A503 DW ANSWR 07C0 47 DB 'G' ; "GOODBYE" HANG UP PHONE 07C1 7005 DW HANGUP 07C3 42 DB 'B' ; CHANGE BAUD RATE 07C4 9005 DW BRATE 07C6 53 DB 'S' ; SET STOP BITS 07C7 F305 DW SBITS 07C9 4C DB 'L' ; SET DATA WORD LENGTH 07CA D305 DW LENGTH 07CC 50 DB 'P' ; SET PARITY MODE 07CD 3406 DW PARTYP 07CF 46 DB 'F' ; SET FULL DUPLEX 07D0 0B06 DW FULL 07D2 48 DB 'H' ; HALF DUPLEX 07D3 2006 DW HALF 07D5 4A DB 'J' ; JUMP TO ADDRESS 07D6 8306 DW JUMP 07D8 43 DB 'C' ; CAPTURE 07D9 8B06 DW CAPTURE 07DB 54 DB 'T' ; TYPE BUFFER TO CONSOLE 07DC 3A07 DW TYPE 07DE 57 DB 'W' ; WRITE CAPTURE BUFFER TO DISK 07DF 0A09 DW SAVE 07E1 52 DB 'R' ; READ AND XMIT DISK FILE 07E2 8908 DW READ 07E4 3F DB '?' ; SET TO DEBUG MODE 07E5 7A07 DW DEBUG 07E7 00 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 ; 07E8 11BD10 DELETE LXI D,FCB 07EB 0E13 MVI C,19 07ED C30500 JMP BDOS ; 07F0 11BD10 MAKE LXI D,FCB 07F3 0E16 MVI C,22 07F5 C30500 JMP BDOS ; 07F8 E5 SETDMA PUSH H 07F9 0E1A MVI C,26 07FB CD0500 CALL BDOS 07FE E1 POP H 07FF C9 RET ;; 0800 E5 WRITENR PUSH H 0801 11BD10 LXI D,FCB 0804 0E15 MVI C,21 0806 CD0500 CALL BDOS 0809 E1 POP H 080A C9 RET ; 080B E5 READNR PUSH H 080C 11BD10 LXI D,FCB 080F 0E14 MVI C,20 0811 CD0500 CALL BDOS 0814 E1 POP H 0815 C9 RET ; 0816 11BD10 CLOSE LXI D,FCB 0819 0E10 MVI C,16 081B C30500 JMP BDOS ; 081E 11BD10 OPEN LXI D,FCB 0821 0E0F MVI C,15 0823 C30500 JMP BDOS ; ; GET NAME OF FILE FROM CONSOLE BUFFER TO FILE CONTROL BLOCK ; 0826 CD9A02 GETNAME CALL NXTCHR ; SET BUFFER POINTER TO FILE NAME 0829 B7 ORA A ; TEST FOR NO FILE NAME 082A C8 RZ ; RETURN IF NONE ENTERED 082B 21BD10 LXI H,ET ; POINT TO ENTRY TYPE 082E AF XRA A ; ZERO A 082F 060C MVI B,12 ; LOAD COPUTER 0831 77 G1 MOV M,A ; FILL FCB AREA WITH 0 + 11 SPACES 0832 3E20 MVI A,20H ; A SPACE 0834 23 INX H ; BUMP POINTER 0835 05 DCR B ; COUNT'EM 0836 C23108 JNZ G1 0839 0608 MVI B,8 ; MAX OF 8 CHAR. IN FILE NAME 083B 11BE10 LXI D,FNAME ; POINT TO FCB FILE NAME AREA 083E CD6108 CALL MVNAM ; MOVE NAME FROM BUFFER TO FCB 0841 FE2E CPI '.' 0843 C24E08 JNZ G2 ; IF NO PERIOD THEN NO FILE TYPE 0846 11C610 LXI D,FTYPE ; POINT TO FILE TYPE AREA 0849 0603 MVI B,3 ; MAX OF 3 CHARS. IN FILE TYPE 084B CD6108 CALL MVNAM ; MOVE TYPE INTO FCB AREA 084E 11C910 G2 LXI D,EX ; FILL REST OF FCB WITH ZEROS 0851 0615 MVI B,(NR+1)-EX ; COUNTER 0853 3600 GG3 MVI M,0 0855 23 INX H 0856 05 DCR B 0857 C25308 JNZ GG3 085A 118000 LXI D,80H ; SET DMA ADDRESS TO 80H 085D CDF807 CALL SETDMA 0860 C9 RET ; ; MOVES STRINGS FROM CONSOLE BUFFER TO FCB AREA ; DE POINT TO DESTINATION ; B HAS NUMBER OF CHARACTERS TO MOVE ; 0861 CD7E02 MVNAM CALL NEXT ; GET NEXT CHARACTER 0864 FE2E CPI '.' ; END OF FILE NAME? 0866 C8 RZ 0867 FE0D CPI CR ; END OF LINE? 0869 C8 RZ 086A FE00 CPI 0 ; DELIMITER? 086C C8 RZ 086D 12 STAX D ; PUT CHARACTER IN FCB 086E 13 INX D ; ADVANCE POINTER 086F 05 DCR B 0870 C26108 JNZ MVNAM ; LOOP IF MORE CHARACTERS 0873 C37E02 JMP NEXT ; GET NEXT CHARACTER AND RETURN 0876 21C910 LXI H,EX ; POINT TO EXTENT AREA OF FCB 0879 0615 MVI B,(NR+1)-EX 087B 3600 G3 MVI M,0 ; FILL REST OF FCB WITH ZERO 087D 23 INX H 087E 05 DCR B 087F C27B08 JNZ G3 0882 118000 LXI D,80H 0885 CDF807 CALL SETDMA 0888 C9 RET ; ; DISK FILE XMIT ROUTINE ; 0889 CD2608 READ CALL GETNAME ; GET FILE NAME 088C CD1E08 CALL OPEN 088F FEFF CPI 255 ; OK? 0891 C2A208 JNZ R1 ; JUMP IF OPEN IS OK 0894 CDDF02 CALL PRINT 0897 4E4F542046 DB 'NOT FOUND',CR 08A1 C9 RET 08A2 CD0B08 R1 CALL READNR ; READ 128 BYTES INTO 80H BUFFER 08A5 CDB108 CALL TXBUF ; XMIT THE BUFFER CONTENTS 08A8 FE1A CPI 1AH ; CONTROL Z (END OF FILE) 08AA C2A208 JNZ R1 08AD CD1608 CALL CLOSE 08B0 C9 RET ; ; TRANSMITTS THE CONTENTS OF THE DISK BUFFER ; 08B1 218000 TXBUF LXI H,80H 08B4 3E80 MVI A,128 08B6 4E TXB1 MOV C,M ; GET A CHARACTER 08B7 CDF904 CALL XMIT ; XMIT IT 08BA 79 MOV A,C 08BB FE1A CPI 1AH ; END OF FILE? 08BD C8 RZ ; YES RETURN 08BE FE0D CPI CR ; END OF LINE? 08C0 CCE408 CZ WTRPLY ; WAIT FOR POSSIBLE PROMPT 08C3 CDF309 CALL RXSTAT ; SEE IF CHAR. HAS BEEN RECEIVED 08C6 B7 ORA A 08C7 C40B05 CNZ CRECV ; GET IT ANDD SEND TO CONSOLE 08CA CDF809 CALL CDSTAT ; CHECK FOR CARRIER 08CD B7 ORA A 08CE CADB08 JZ ABRT ; ABORT IF NO CARRIER 08D1 CDA909 CALL CONST ; WANT TO ABORT? 08D4 B7 ORA A 08D5 CADE08 JZ TXB2 ; JUMP IF NOT 08D8 CD9D09 CALL CONIN ; ABORT ON ANY KEY PRESSED 08DB 3E1A ABRT MVI A,1AH ; FAKE OUT THE CALLING ROUTINE 08DD C9 RET 08DE 23 TXB2 INX H ; BUMP BUFFER POINTER 08DF 05 DCR B ; COUNT BYTES 08E0 C2B608 JNZ TXB1 08E3 C9 RET ; ; THIS ROUTINE WAITS FOR 150 M S AFTEER THE LAST ; CHARACTER IS RECEIVED BY THE M ODEM. ; 08E4 C5 WTRPLY PUSH B 08E5 CDF309 CALL RXSTAT 08E8 B7 ORA A 08E9 C4E909 CNZ RXCHR ; FLUSH UART 08EC 0603 WTRP1 MVI B,3 ; 150 MS 08EE CDB40A WTRP2 CALL STIME ; START TIMER 08F1 CDF309 WTRP3 CALL RXSTAT ; MODEM CHAR. RECEIVED? 08F4 B7 ORA A 08F5 F5 PUSH PSW ; SAVE STATUS 08F6 C40B05 CNZ CRECV ; GET AND SEND TO CONSOLE 08F9 F1 POP PSW ; POP FLAGS AGAIN 08FA C2EC08 JNZ WTRP1 ; IF CHARACTER REC. LOOP BACK 08FD CDB70A CALL CKTIME ; TIMES UP? 0900 B7 ORA A 0901 CAF108 JZ WTRP3 ; NO, LOOP BACK 0904 05 DCR B ; COUNT LOOPS 0905 C2EE08 JNZ WTRP2 ; LOOP IF NOT 150 MS 0908 C1 POP B ; RESTORE BC 0909 C9 RET ;; ; THIS ROUTINE STORES THE CONTENTS OF THE CAPTURE ; BUFFER ON THE DISK. ; 090A CD2608 SAVE CALL GETNAME 090D CDE807 CALL DELETE ; ERASE OLD FILE OF SAME NAME 0910 CDF007 CALL MAKE ; MAKE NEW FILE 0913 FEFF CPI 255 0915 C22F09 JNZ S1 0918 CDDF02 CALL PRINT 091B 4E4F204449 DB 'NO DIRECTORY SPACE',CR 092E C9 RET 092F CD1E08 S1 CALL OPEN 0932 2A3610 LHLD CBUFP ; CAPTURE BUFFER POINTER 0935 EB XCHG ; POINTER TO DE 0936 2A3810 LHLD CPCNT ; BUFFER CHARACTER COUNT 0939 3E1A S2 MVI A,1AH ; ENDD OF FILE MARKER 093B 12 STAX D 093C 13 INX D 093D 23 INX H ; FILL OUT WITH 1A'S TILL 093E 7D MOV A,L ; EVEN WITH 128 BYTE BOUNDRY 093F E67F ANI 7FH 0941 C23909 JNZ S2 0944 29 DAD H ; SHIFT HL LEFT 1 BIT 0945 CE00 ACI 0 ; SHIFT CARRY INTO REG. A 0947 47 MOV B,A ; MSB OF RECORDDD COUNT TO B 0948 4C MOV C,H ; LSB OF RECORD COUNT IN C 0949 03 INX B ; ADD 1 MORE 094A 11DE10 LXI D,CPBUF ; CAPTURE BUFFER START ADDRESS 094D C5 S3 PUSH B ; SAVE RECORD COUNT 094E D5 PUSH D ; SAVE BUFFER POINTER 094F CDF807 CALL SETDMA ; DMA=BUFFER 0952 CD0008 CALL WRITENR ; WRITE A RECORD TO DISK 0955 B7 ORA A ; CHECK FOR ERROR 0956 C28A09 JNZ ERRR 0959 D1 POP D ; GET CAPTURE BUFFER POINTER 095A 218000 LXI H,128 095D 19 DAD D ; ADVANCE IT 128 BYTES 095E EB XCHG 095F C1 POP B ; GET RECORD COUNT 0960 0B DCX B ; COUNT 1 0961 78 MOV A,B 0962 B1 ORA C ; TEST FOR ZERO 0963 C24D09 JNZ S3 ; IF NOT ZERO, LOOP BACK 0966 118000 LXI D,80H ; RESET DMA TO 80H 0969 CDF807 CALL SETDMA 096C CD1608 CALL CLOSE 096F FEFF CPI 255 0971 C2D006 JNZ RSBUF ; CLEAR CAPTUREE BUFFER 0974 CDDF02 CALL PRINT 0977 43414E4E4F DB 'CANNOT CLOSE FILE',CR 0989 C9 RET 098A E1 ERRR POP H 098B E1 POP H ; CLEAN UP STACK 098C CDDF02 CALL PRINT 098F 4F5554204F DB 'OUT OF SPACE',CR 099C C9 RET ; ;***** CONSOLE I/O AREA FOR CP/M ***** ; ; CONSOLE INPUT ; IT RETURNS THE CHARACTER IN REG. A ; 099D E5 CONIN PUSH H 099E D5 PUSH D 099F C5 PUSH B 09A0 CD0A10 CALL XCONIN 09A3 E67F ANI 7FH ; KILL MSB 09A5 C1 POP B 09A6 D1 POP D 09A7 E1 POP H 09A8 C9 RET ;; ; CONSOLE STATUS CHECK ; REETURNS WITH A=0 IF NO CHARACTER TYPED ; OR A=1 IF CHARACTER HAS BEEEN TYPED (OR A=NOT ZERO) ; 09A9 E5 CONST PUSH H 09AA D5 PUSH D 09AB C5 PUSH B 09AC CD0710 CALL XCONST 09AF C1 POP B 09B0 D1 POP D 09B1 E1 POP H 09B2 C9 RET ; ; CONSOLE OUTPUT. CHARACTER TO BE PRINTED MUST BE IN ; REG. C ; 09B3 E5 CONOUT PUSH H 09B4 D5 PUSH D 09B5 C5 PUSH B 09B6 CD0D10 CALL XCONOT 09B9 C1 POP B 09BA D1 POP D 09BB E1 POP H 09BC C9 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. ; 09BD 2A0100 INIT LHLD 1 ; GET ADDRESS OF CBIOS 09C0 110410 LXI D,JTAB ; DESTINATION ADDRESS 09C3 060C MVI B,4*3 ; NO. OF BYTES TO MOVE 09C5 7E MOVE MOV A,M ; GET A BYTE 09C6 12 STAX D ; MOVE IT 09C7 23 INX H ; ADVANCE POINTERS 09C8 13 INX D 09C9 05 DCR B 09CA C2C509 JNZ MOVE ; COUNT BYTES 09CD 3E01 MVI A,1 ; SPECIAL HARDWARE STUFF 09CF D384 OUT 84H 09D1 C9 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 ; 0080 = DATA EQU 80H 0081 = STATUS EQU DATA+1 0081 = CR1 EQU DATA+1 0082 = CR2 EQU DATA+2 0083 = CR3 EQU DATA+3 ; ; BIT FUNCTIONS ; STATUS REGISTER ; 0001 = RRF EQU 1 ; RECEIVE REGISTER FULL 0002 = TRE EQU 2 ; XMIT HOLDING REGISTER EMPTY 0004 = PE EQU 4 ; PARITY ERROR 0008 = FE EQU 8 ; FRAMMING ERROR 0010 = OE EQU 10H ; OVERRUN ERROR 0020 = TMR EQU 20H ; TIMER STATUS 0040 = CD EQU 40H ; CARRIER PRESENT 0080 = RI EQU 80H ; NOT RING INDICATOR (LOW TRUE) ; ; CONTROL REGISTER 1 (CR1) ; 0001 = EPE EQU 1 ; EVEN PARITY ENABLE 0002 = LS1 EQU 2 ; WORD LENGTH SELECT BIT 1 0004 = LS2 EQU 4 ; WORD LENGTH SELECT BIT 2 0008 = SBS EQU 8 ; STOP BITS 0010 = PI EQU 10H ; PARITY INHIBIT 0020 = TMIE EQU 20H ; TIMER INTERUPTS ENABLE ; ; CONTROL REGISTER 2 (CR2) ; 0001 = BRS EQU 1 ; BAUD RATE CONTROL 0002 = TXE EQU 2 ; XMIT CARRIER ENABLE 0004 = MS EQU 4 ; MODE (0=ANSWER, 1=ORIGINATE) 0008 = BRK EQU 8 ; SEND BREAK 0010 = ST EQU 10H ; SELF TEST 0020 = TIE EQU 20H ; XMIT INTERUPT ENABLE 0040 = RIE EQU 40H ; RECEIVER INTRUPT ENABLE 0080 = 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 ; 09D2 AF RESET XRA A ; ZERO A 09D3 D381 OUT CR1 09D5 D382 OUT CR2 09D7 320110 STA MICR2 ; CLEAR MEMORY IMAGES TOO 09DA 320010 STA MICR1 09DD C9 RET ; ; THIS ROUTINE SENDS A BYTE IN REGISTER C TO THE MODEM ; TRANSMITTER. ONLY REGISTER A IS DISTURBED ; 09DE DB81 TXCHR IN STATUS ; GET MODEM STATUS 09E0 E602 ANI TXE ; CHECK FOR XMITER EMPTY 09E2 CADE09 JZ TXCHR ; LOOP IF NOT 09E5 79 MOV A,C 09E6 D380 OUT DATA ; SEND IT 09E8 C9 RET ; ; GETS A BYTE FROM THE MODEM RECEIVER IN REGISTER A ; 09E9 DB81 RXCHR IN STATUS 09EB E601 ANI RRF 09ED CAE909 JZ RXCHR ; LOOP IF NO CHARACTER REC. 09F0 DB80 IN DATA 09F2 C9 RET ; CHARACTER IN A ; ; THIS ROUTINE RETURNS WITH A=1 IF A RECEIVED ; CHARACTER IS WAITING OR A=0 IF NOT. ; 09F3 DB81 RXSTAT IN STATUS ; GET MODEM STATUS 09F5 E601 ANI RRF ; CHECK RECEIVEER FLAG 09F7 C9 RET ; A=1 IF CHARACTER PRESENT ; ; CARRIER STATUS CHECK. A=1 IF CARRIER IS PRESENT ; 09F8 DB81 CDSTAT IN STATUS 09FA E640 ANI CD ; TEST CARRIER DETECT FLAG 09FC 3E00 MVI A,0 ; ASSUME 0 09FE C8 RZ 09FF 3C INR A ; MAKE A=1 IF CARRIER PRESENT 0A00 C9 RET ; ; RING INDICATOR STATUS CHECK. A=1 IF PHONE RINGING ; 0A01 DB81 RISTAT IN STATUS 0A03 E680 ANI RI 0A05 3E01 MVI A,1 ; ASSUME RINGING 0A07 C8 RZ ; RETURN IF IT IS (LOW TRUE BIT) 0A08 3D DCR A ; ELSE MAKE A=0 0A09 C9 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 ; 0A0A DB81 ERFLG IN STATUS 0A0C 1F1F RAR!RAR! ; SHIFT BITS RIGHT 2 PLACES 0A0E E607 ANI 7 ; KILL UNWANTED BITS 0A10 C9 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 ; 0A11 79 TXON MOV A,C 0A12 B7 ORA A 0A13 3E02 MVI A,TXE ; PUT TXE BIT IN A 0A15 CAFD0A JZ CLR2 ; CLEAR IT IF 0 0A18 C3F30A 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) ; 0A1B 79 BAUD MOV A,C 0A1C B7 ORA A 0A1D 3E01 MVI A,BRS ; BAUD RATE BIT IN A 0A1F CAFD0A JZ CLR2 ; RESET BIT IF 0 0A22 C3F30A JMP SET2 ; SET IF 1 ; ; GO ON/OFF HOOK. C=0 FOR ON-HOOK (IDLE) ; C=1 FOR OFF-HOOK. ; 0A25 79 SWHOOK MOV A,C 0A26 B7 ORA A 0A27 3E80 MVI A,OH ;; SWITCH-HOOK BIT 0A29 CAFD0A JZ CLR2 0A2C C3F30A JMP SET2 ; ; GET SWITCH HOOK STATUS. ; A=0 ON HOOK A=1 OFF HOOK ; 0A2F 3A0110 SHSTAT LDA MICR2 ; GET CR2 0A32 E680 ANI OH ; MASK FOR OFF HOOK 0A34 3E01 MVI A,1 0A36 C0 RNZ ; RETURN IF OFF HOOK A=1 0A37 3D DCR A 0A38 C9 RET ; ELSE A=0 ; ; SET THE MODE. C=0 FOR ANSWEER MODE ; C=1 FOR ORIGINATE MODE ; 0A39 79 MODE MOV A,C 0A3A B7 ORA A 0A3B 3E04 MVI A,MS ; MODE SELECT BIT 0A3D CAFD0A JZ CLR2 0A40 C3F30A JMP SET2 ; ; SET OR CLEAR SELF-TEST MODE. ; C=1 FOR SELF TEST C=0 FOR NORMAL ; 0A43 79 SELFT MOV A,C 0A44 B7 ORA A 0A45 3E10 MVI A,ST ; SELF-TEST BIT 0A47 CAFD0A JZ CLR2 ; CLEAR IT 0A4A C3F30A 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 ; 0A4D C5 BREAK PUSH B ; SAVE BREAK DURATION VALUE 0A4E 0E02 MVI C,2 0A50 CDA10A CALL DELAY ; WAIT 100 MS 0A53 C1 POP B ; RESTORE BREAK DURATION VALUE 0A54 E5 PUSH H 0A55 210110 LXI H,MICR2 0A58 3E08 MVI A,BRK ; SET THE BREAK BIT 0A5A B7 ORA A 0A5B D382 OUT CR2 0A5D CDA10A CALL DELAY ; C=50 MS INTERVALS TO WAIT 0A60 3E08 MVI A,BRK 0A62 2F CMA 0A63 A6 ANA M ; CLEAR BREAK BIT 0A64 D382 OUT CR2 ; WRITE IT TO MODEM 0A66 E1 POP H 0A67 C9 RET ; ; SETS THE PARITY. C=0 FOR NO PARITY ; C=11 FOR ODD PARITY C=2 FOR EVEN PARITY ; 0A68 79 PARITY MOV A,C 0A69 B7 ORA A ; TEST FOR NO PARITY 0A6A CA7E0A JZ PAROFF 0A6D 3E10 MVI A,PI 0A6F CD120B CALL CLR1 ; CLEAR PARITY INHIBIT BIT 0A72 79 MOV A,C 0A73 1F RAR ; LSB IS NO EVEN/ODD PARITY 0A74 E601 ANI 1 0A76 3E01 MVI A,EPE 0A78 CA120B JZ CLR1 ; CLEAR EPE IF ODD 0A7B C3080B JMP SET1 ; SET EPE IF EVEN 0A7E 3E10 PAROFF MVI A,PI 0A80 C3080B JMP SET1 ; INHIBIT PARITY ; ; SELECT WORD LENGTH. ; C=NUMBER OF DATA BITS (5,6,7,8) ; 0A83 79 WLS MOV A,C 0A84 D605 SUI 5 ; REMOVE BIAS 0A86 87 ADD A ; SHIFT LEFT 1 PLACE 0A87 E606 ANI 6 ; KILL ANY STRAY BITS 0A89 4F MOV C,A ; SAVE RESULT IN C 0A8A 3A0010 LDA MICR1 ; GET MEMORY IMAGE 0A8D E6F9 ANI NOT LS1+LS2 ; CLEAR WORD LENGTH BITS 0A8F B1 ORA C ; PUT IN NEW ONES 0A90 320010 STA MICR1 ; UPDATE MEMORY 0A93 D381 OUT CR1 ; WRITE TO MODEM 0A95 C9 RET ; ; SET NUMBER OF STOP BITS ; C=STOP BITS (1 OR 2) ; 0A96 79 NSTOP MOV A,C 0A97 D601 SUI 1 0A99 3E08 MVI A,SBS ; STOP BIT SELECT BIT 0A9B CA120B JZ CLR1 ; CLEAR IT 0A9E C3080B JMP SET1 ; ELSE SET IT ; ; DELAY ROUTINE. ; ; WAITS 50 MS TIMES THE VALUE IN REGISTER C. ; 0AA1 79 DELAY MOV A,C 0AA2 B7 ORA A 0AA3 C8 RZ ; WAIT ZERO TIME IF C=0 0AA4 C5 PUSH B ; SAVE CONTENTS OF C 0AA5 D383 DLY1 OUT CR3 ; START TIMER 0AA7 DB81 DLY2 IN STATUS ; WAIT TILL IT TIMES OUT 0AA9 E620 ANI TMR ; LOOK AT TIMER BIT 0AAB CAA70A JZ DLY2 ; LOOP BACK IF ZERO 0AAE 0D DCR C ; COUNT DOWN 0AAF C2A50A JNZ DLY1 ; DO AGAIN IF NOT ZERO 0AB2 C1 POP B 0AB3 C9 RET ; ; STARTS THE 50 MS TIMER ; 0AB4 D383 STIME OUT CR3 ; START TIMER 0AB6 C9 RET ; ; CHECKS THE STATUS OF THE TIMER. ; RETURNS WITH A=1 IF TIMED OUT OR A=0 IF NOT. ; 0AB7 DB81 CKTIME IN STATUS 0AB9 E620 ANI TMR ; MASK IN TIMER BIT 0ABB 3E01 MVI A,1 0ABD C0 RNZ ; RET. A=1 IF TIMED OUT 0ABE 3D DCR A 0ABF C9 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. ; 0AC0 C5 DLTONE PUSH B 0AC1 0E01 MVI C,1 0AC3 CD250A CALL SWHOOK ; GO OFF-HOOK 0AC6 0E28 MVI C,40 ; 40*50MS=2 SECONDS 0AC8 CDA10A CALL DELAY ; WAIT 2 SECONDS 0ACB C1 POP B ; RESTORE BC 0ACC C9 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. ; 0ACD C5 PULSE PUSH B ; SAVE BC 0ACE 79 MOV A,C 0ACF 060A MVI B,10 ; PRE-LOAD PULSE COUNTER 0AD1 E60F ANI 0FH ; KILL POSSIBLE ASCII BIAS 0AD3 FE00 CPI 0 ; SEE IF WE'RE DOING 10 PULSES 0AD5 CAD90A JZ PULS1 0AD8 47 MOV B,A ; PULSE COUNT IN B 0AD9 0E00 PULS1 MVI C,0 ; GO ON HOOK 0ADB CD250A CALL SWHOOK 0ADE 0E01 MVI C,1 0AE0 CDA10A CALL DELAY ; WAIT 50 MS 0AE3 0E01 MVI C,1 0AE5 CDA10A CALL DELAY ; WAIT 50 MS 0AE8 05 DCR B ; WE MADDE 1 PULSE, COUNT IT 0AE9 C2D90A JNZ PULS1 ; IF NOT ZERO, MAKE SOME MORE 0AEC 0E0B MVI C,11 ; 11*50 MS=550 MS 0AEE CDA10A CALL DELAY ; INTER-DIGIT DELAY 0AF1 C1 POP B ; RESTORE BC 0AF2 C9 RET ; ; SETS BITS IN CONTROL REGISTER 2. ; ENTER WITH REG. A CONTAINING 1'S WHERE BITS ARE TO BE ; SET. ; 0AF3 E5 SET2 PUSH H 0AF4 210110 LXI H,MICR2 0AF7 B6 ORA M ; OR IN BITS TO BE SET 0AF8 77 MOV M,A 0AF9 D382 OUT CR2 ; SET THE MODEM 0AFB E1 POP H 0AFC C9 RET ; ; CLEAR BITS IN CONTROL REGISTER 2 ; REG. A HAS 1'S FOR BITS TO BE CLEARED. ; 0AFD E5 CLR2 PUSH H 0AFE 210110 LXI H,MICR2 ; MEMORY IMAGE OF CR2 0B01 2F CMA 0B02 A6 ANA M ; TURN OFF THE BIT 0B03 77 MOV M,A ; UPDATE MEMORY 0B04 D382 OUT CR2 ; WRITE TO CRL. REG. 2 0B06 E1 POP H 0B07 C9 RET ; ; SET BITS IN CONTROL REGISTER 1 ; REG A HAS 1'S IN BITS TO BE SET ; 0B08 E5 SET1 PUSH H 0B09 210010 LXI H,MICR1 0B0C B6 ORA M 0B0D 77 MOV M,A 0B0E D381 OUT CR1 0B10 E1 POP H 0B11 C9 RET ; ; CLEAR BITS IN CONTROL REG 1 ; REG A HAS 1'S IN BITS TO BE CLEARED ; 0B12 E5 CLR1 PUSH H 0B13 210010 LXI H,MICR1 0B16 2F CMA 0B17 A6 ANA M 0B18 77 MOV M,A 0B19 D381 OUT CR1 0B1B E1 POP H 0B1C C9 RET ; * * * * * * * ; THIS AREA MUST BE R/W MEMORY ; ; ; 1000 ORG 1000H ; RAM MEMORY AREA SOR ; START OF RAM 1000 MICR1 DS 1 ; MEMORY IMAGE OF CONTROL REG. 1 1001 MICR2 DS 1 ; MEMORY IMAGE OF CONTROL REG. 2 1002 DPLX DS 1 ; FULL DUPLES FLAG 1=FULL, 0=HALF 1003 MFLAG DS 1 ; O=ANSWER,1=ORIGINATE 1004 JTAB DS 3 ; CBIOS JUMP TABLE IS MOVED HERE 1007 XCONST DS 3 ; CONSOLE STATUS 100A XCONIN DS 3 ; CONSOLE INPUT 100D XCONOT DS 3 ; CONSOLE OUTPUT 1010 NMBR DS 32 ; 32 BYTES PHONE NUMBER STORAGE 1030 BUFPNT DS 2 ; BUFFER POINTER STORAGE 1032 CPFLAG DS 1 ; CAPTURE FLAG 1=ON, 0=OFF 1033 BUGFLAG DS 1 ; 1=DEBUG MODE 0=NORMAL 1034 BUGCOUNT DS 1 ; COUNTS HEX BYTES PER LINE 1035 MTOP DS 1 ; TOP OF MEMORY (PAGE) 1036 CBUFP DS 2 ; CAPTURE BUFFER POINTER 1038 CPCNT DS 2 ; CAPTURED CHARACTER COUNTER EOR ; ENDD OF RAM CHECKED BY CHECKSUM 103A CKSUM DS 1 ; CHECKSUM STORED HERE 103B DS 64 107B STACK DS 1 ; 64 BYTES FOR STACK 107C BUF DS 65 ; CONSOLE BUFFER ; ; CPM FILE CONTROL BLOCK ; FCB 10BD ET DS 1 ; ENTRY TYPE 10BE FNAME DS 8 ; FILE NAME 10C6 FTYPE DS 3 ; FILE TYPE 10C9 EX DS 3 ; EXTENT 10CC RCC DS 1 ; RECORD COUNT 10CD DM DS 16 ; DISK MAP 10DD NR DS 1 ; NEXT RECORD 10DE CPBUF DS 1 ; CAPTURE BUFFER 10DF END START ; THATS ALL FOLKS