; ; ---- MODEM REMOTE CONSOLE PROGRAM ---- ; VERSION 1.1 ; ----- TRS-80 MODEL III EQUATES ----- ; (ORIGINAL) ; (--- VERSION FOR OSBORNE O-1 ---) ; BY BRK ; ; revised by Jim Woolley, FOG Disk Librarian, 11/82 ; ;***** MODIFIED by Garry Pribble 02/12/85 ***** ;++++++Modified by Steven A. Bland 2/13/85++++++ ; ; THIS PROGRAM ATTACHES A REMOTE CONSOLE, TYPICALLY ; THRU A MODEM CHANNEL, IN PARALLEL WITH THE USUAL ; CP/M CONSOLE DEVICE. IN THIS MODE, CHARACTERS TYPED ; ON EITHER CONSOLE ARE ECHOED TO BOTH. THIS ALLOWS ; A REMOTE USER TO CONTROL THE COMPUTER ... TO RUN ; DIAGNOSTICS... OR TO GIVE INSTRUCTION ON HOW TO ; PERFORM CERTAIN OPERATIONS. ; ; THE PROGRAM IS INITIATED BY THE COMMAND: ; ; A>REMOTE ; OR ; A>REMOTE XXXX ; WHERE XXXX IS A HEX MEMORY ADDRESS ; ; IN THE FIRST CASE, THE MODEM DRIVERS WILL BE RELOCATED AND ; COPIED JUST UNDER THE CCP ( OR JUST UNDER WHATEVER PROGRAM ; IS ALREADY PROTECTED UNDER THE CCP ). IN THIS MODE, WARM BOOTS ; ARE DISABLED. IN THE SECOND CASE, WHEN A HEX MEMORY ADDRESS ; IS SPECIFIED, THE MODEM DRIVERS ARE RELOCATED AND COPIED TO THIS ; ADDRESS (ASSUMED TO BE "ABOVE" THE BIOS). ; ; THE DRIVERS MAY BE DETACHED BY RUNNING THE PROGRAM AGAIN. IT WILL ; LOAD AND IF IT FINDS MODEM DRIVERS ALREADY ATTACHED, IT WILL ASK ; IF YOU WANT THEM DISCONNECTED. ; ; ---- CP/M EQUATES ---- ; BDOS EQU 5 ; FUNCTION CALL ENTRY POINT FCB EQU 5CH ; DEFAULT FCB LOCATION CDISC EQU 4 ; BUFFER FOR LOGGED ON DRIVE # CHOUT EQU 2 ; BDOS COMMAND FOR CONSOLE OUTPUT LST EQU 9 ; BDOS COMMAND TO PRINT A STRING DIO EQU 6 ; BDOS COMMAND FOR DIRECT I/O ( CP/M 2.X ) ; CR EQU 0DH ; CARRIAGE RETURN LF EQU 0AH ; LINE FEED ; ; ORG 100H ; JMP START ; JUMP OVER MSG DB 'REMOTE CONSOLE PGM V1.1, (C) 1982 BY BRK',1AH ; START: POP H ; GET RETURN ADDRESS FROM STACK LXI SP,STACK ; SET NEW STACK PUSH H ; PUT RETURN ADDRESS ON NEW STACK ; LXI D,STMSG ; POINT TO STARTUP MESSAGE CALL PTMSG ; ANNOUNCE PRESENCE ; XRA A STA ABOVE ; INIT ABOVE FLAG TO "BELOW" STATUS ; LHLD 1 ; GET POINTER TO BIOS+3 SHLD BIOS3 ; SET INTO PROGRAM MODULE LXI D,-1600H DAD D ; COMPUTE ADDRESS OF CCP+3 (CP/M 2.X) SHLD CCP3 ; SAVE IN PROGRAM MODULE LXI D,1621H ; OFFSET TO BIOS SETDMA LOCATION DAD D SHLD STDMA ; SET IN PROGRAM MODULE ; LHLD 6 SHLD BDJ+1 ; SAVE BDOS ENTRY ADDRESS ; LHLD 1 LXI D,4 DAD D ; POINT TO BIOS+7 MOV E,M ; GET ADDRESS OF CONSOLE STATUS ROUTINE INX H MOV D,M XCHG LXI D,-10 ; LENGTH OF POSSIBLE TEST STRING+POINTER DAD D ; POINT TO POSSIBLE START OF STRING LXI D,TMSG ; POINT TO TEST STRING MVI C,8 ; SET COMPARISON LENGTH CALL COMPARE ; COMPARE THEM SHLD CDPTR ; SAVE POSSIBLE POINTER JNZ INSTALL ; IF NOT EQUAL, ASSUME NO MODEM DRIVER IS ; ; ATTACHED ALREADY LXI D,ALMSG ; IF DRIVER IS ATTACHED, ASK TO DETACH CALL PTMSG CALL YES RNZ ; IF "NO", JUST RETURN ; LXI D,DTMSG CALL PTMSG ; NOTIFY OF DETACHMENT ; LHLD CDPTR CALL GTDE ; GET POINTER TO OLD JUMP TABLE IN MODULE LHLD 1 ; GET POINTER TO STD JUMP TABLE XCHG LXI B,12 ; LENGTH OF TABLE CALL MOVE ; DETACH MODULE JMP EXIT ; DO WARM BOOT TO RE-INIT BASE PAGE JUMPS ; INSTALL: LXI H,FCB+1 ; POINT TO STD CP/M FCB LOCATION SHLD CHPTR ; SAVE FOR HEX ROUTINE MOV A,M ; GET FIRST CHAR. CALL THEX ; CHECK IF VALID HEX # JC BELOW ; IF NOT, PUT MODULE "BELOW" CALL GTHEX ; IF VALID, TRY TO EXTRACT HEX NUMBER SHLD LDADDR ; SAVE IT MVI A,1 STA ABOVE ; SET ABOVE MODE JC INST1 ; IF GOOD HEX VALUE LXI D,EMSG1 JMP EXMG ; EXIT WITH ERROR MESSAGE ; INST1: PUSH H LHLD 1 ; GET BIOS+3 LXI D,40H ; ASSUME JUMP TABLE AT LEAST DAD D POP D CALL COMPDE ; IS # REALLY ABOVE THE BIOS JC INSTA ; IF IT LOOKS OK ; LXI D,EMSG2 JMP EXMG ; " ABOVE ADDRESS IS TOO SMALL" ; AND EXIT BACK TO CP/M ; BELOW: LHLD CCP3 ; GET ADDRESS OF CCP+3 XCHG LHLD BDOS+1 ; GET BDOS ENTRY JUMP ADDRESS CALL COMPDE ; COMPARE THEM JC INST2 ; IF CCP+3>BDOS ENTRY XCHG INST2: LXI D,-LENC-10 DAD D ; ALLOW ROOM BELOW FOR CODE MVI L,6 ; MAKE START ADDRESS LIKE BDOS ENTRY SHLD LDADDR ; SAVE ADDRESS TO COPY MODULE TO ; INSTA: LHLD 1 ; POINT TO PART OF BIOS JUMP TABLE LXI D,OWBOOT ; POINT TO DESTINATION IN MODULE LXI B,12 ; LENGTH OF TABLE CALL MOVE ; COPY INTO MODULE ; LXI D,BDJ ; POINT TO START OF MODULE LHLD LDADDR ; POINT TO CODE DESTINATION CALL SUBDE SHLD OFFSET ; SAVE RELOCATION OFFSET CALL RELOC ; RELOCATE CODE IN MODULE ; LHLD LDADDR ; SET DESTINATION ADDRESS XCHG LXI H,BDJ ; SET SOURCE ADDRESS LXI B,LENC+1; SET LENGTH OF CODE IN MODULE CALL MOVE ; COPY MODULE TO DESTINATION ; LHLD 1 XCHG ; GET BIOS+3 IN (D,E) ; LXI H,NWBOOT ; POINT TO NEW JUMP TABLE LXI B,12 ; LENGTH OF TABLE LDA ABOVE ORA A ; TEST IF "ABOVE" MODE JZ INST3 ; NO, SO DO MOVE INX D ; YES, SO DO NOT COPY OVER WARM BOOT JUMP INX D INX D LXI H,NWBOOT+3 LXI B,9 INST3: CALL MOVE ; LINK IN MODULE BY SWITCHING IN JUMP TABLE ; CALL MXINIT ; INIT REMOTE DRIVERS deleted, jw LXI D,ATMSG CALL PTMSG LHLD LDADDR ; GET LOAD ADDRESS CALL HEXW ; PRINT IT OUT LXI D,ATMSG1 JMP EXMG ; LET WARM BOOT CORRECT BASE PAGE JUMPS ; ; ------ SUBROUTINES ------ ; ; --- COMPARE STRINGS AT (H,L) AND (D,E) FOR (C) BYTES --- ; COMPARE: LDAX D CMP M RNZ ; IF NO MATCH INX H INX D DCR C ; COUNT DOWN JNZ COMPARE ; LOOP UNTIL ERROR OR DONE RET ; ; --- COMPARE (H,L) & (D,E) BY SUBTRACTION (H,L)-(D,E) --- ; COMPDE: MOV A,L SUB E MOV A,H SBB D RET ; ; --- SUBTRACT: (H,L)=(H,L)-(D,E) --- ; SUBDE: MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A RET ; ; --- COPY CODE FROM (H,L) TO (D,E) FOR (B,C) BYTES --- ; MOVE: MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ MOVE RET ; ; --- TEST & CONVERT CHAR. IF VALID HEX # --- ; THEX: SUI '0' ; REMOVE ASCII BIAS RC ; IF ERROR CPI 'G'-'0' CMC RC ; IF ERROR CPI 10 ; IS IT 0-9? CMC RNC ; YES, SO RETURN SUI 7 CPI 10 ; IF NOT A-F, SET CARRY RET ; ; --- GET 16 BIT WORD POINTED TO BY (H,L) INTO (D,E) --- ; GTDE: MOV E,M INX H MOV D,M INX H RET ; ; --- PUT 16 BIT WORD FROM (D,E) INTO MEMORY AT (H,L) --- ; PTDE: MOV M,E INX H MOV M,D INX H RET ; ; ; --- HEX INPUT ROUTINE ---- ; GTHEX: LXI H,0 ; CLEAR CONVERSION REGISTER H1: CALL GTCHR ; GET CHAR. CPI CR ; IS IT A CR RZ ; YES, SO RETURN HEX2: CALL THEX ; TEST CHAR. AND REMOVE ASCII BIAS RC ; IF ERROR HEX1: DAD H ; SHIFT 16 BIT REGISTER OVER 4 PLACES DAD H DAD H DAD H ADD L ; ADD IN NEW NIBBLE MOV L,A JMP H1 ; GTCHR: PUSH H LHLD CHPTR ; POINT TO CHAR. MOV A,M ; GET IT INX H SHLD CHPTR ; POINT TO NEXT ONE POP H RET ; ; --- OUTPUT BYTE IN ACC IN HEX --- ; HEXOT: PUSH PSW ; SAVE BYTE RRC ; SHIFT UPPER NIBBLE DOWN RRC RRC RRC CALL HEXB ; OUTPUT UPPER NIBBLE IN HEX POP PSW ; GET BYTE BACK HEXB: ANI 0FH ; MASK OFF UPPER NIBBLE ADI '0' ; ADD ASCII BIAS CPI '9'+1 ; TEST IF NUMERIC JC PRT ; YES, SO DO IT ADI 7 ; NO, SO ADD BIAS FOR A-F PRT: MOV C,A ; SETUP FOR OUTPUT COUT: PUSH PSW PUSH H ; BUFFERED CONSOLE OUTPUT PUSH D PUSH B MOV E,C MVI C,CHOUT ; BDOS CHAR. OUTPUT COMMAND CALL BDOS POP B POP D POP H POP PSW RET ; ; --- OUTPUT (H,L) IN HEX --- ; HEXW: PUSH H MOV A,H CALL HEXOT ; PRINT OUT UPPER BYTE POP H MOV A,L JMP HEXOT ; PRINT OUT LOWER BYTE ; ; --- PRINT STRING POINTED TO BY (D,E) --- ; PTMSG: MVI C,LST JMP BDOS ; ; ; -- YES FUNCTION -- ; YES: CALL CONNC ; GET CONSOLE CHAR. CPI 'Y' ; IS IT A Y? JZ YES1 CPI 'N' ; IS IT A N? JNZ YES ; IF NEITHER, KEEP TRYING INR A ; SET N STATUS YES1: PUSH PSW ; SAVE FLAGS CALL COUT ; OUTPUT TO CONSOLE POP PSW ; RESTORE FLAGS RET CONNC: CALL CONIN ; GET CHAR. FROM CONSOLE MOV C,A ; SAVE FOR ECHO CPI 60H ; IS IT LOWER CASE? JC CON1 ; NO, SO CONTINUE ANI 5FH ; YES, SO MASK TO UPPER CASE CON1: CPI 'C'-40H ; IS IT A CONTROL-C? RNZ ; NO, SO RETURN CTC: LXI D,CMSG ; POINT TO CONTROL-C MESSAGE EXMG: CALL PTMSG ; ISSUE MESSAGE EXIT: LXI D,CRLF CALL PTMSG ; ISSUE A CRLF JMP 0 ; CONIN: MVI E,0FFH MVI C,DIO CALL BDOS ORA A JZ CONIN RET ; ; --- RELOCATE ADDRESSES POINTED TO BY ADDRESS TABLE --- ; RELOC: LXI H,RELTAB ; POINT TO ADDRESS TABLE REL1: CALL GTDE ; GET POINTER INTO (D,E) MOV A,D ORA E ; TEST IF ADDRESS IS ZERO RZ ; RETURN (DONE) IF IT IS PUSH H ; SAVE TABLE POINTER XCHG ; GET ADDRESS INTO (H,L) PUSH H ; SAVE POINTER CALL GTDE ; GET REFERENCED ADDRESS WORD LHLD OFFSET ; GET OFFSET DAD D ; COMPUTE RELOCATED ADDRESS XCHG POP H CALL PTDE ; UPDATE ADDRESS WORD IN CODE POP H ; GET TABLE ADDRESS POINTER BACK JMP REL1 ; LOOP UNTIL DONE ; ; --- RELOCATION ADDRESS TABLE --- ; RELTAB EQU $ DW NWBOOT+1 DW NWBOOT+4 DW NWBOOT+7 DW NWBOOT+10 DW PTX00 DW PTX0+1 DW MCNST+1 DW MCNIN+1 DW PTX1+1 DW PTX2+1 DW PTX3+1 DW PTX4+1 DW PTX41+1 DW PTX5+1 DW PTX6+1 DW PTX7+1 DW DVX1+1 DW MXIN+1 DW DVX2+1 DW DVX3+1 DW DVX4+1 DW 0 ; TABLE TERMINATOR ; ; --- MESSAGES ----- ; STMSG: DB CR,LF DB CR,LF,' --- REMOTE CONSOLE ATTACHMENT PROGRAM ---' DB CR,LF,' VERS. 1.2' DB CR,LF,' FOR TRS-80 III RS-232 PORT' DB CR,LF,' by BRK (TRS-80 3 by Garry Pribble and)' DB CR,LF,' Steven A. Bland' DB CR,LF,'$' ; ALMSG: DB CR,LF,07,' REMOTE CONSOLE IS ALREADY ATTACHED' DB CR,LF,' ----------------> DETACH IT (Y/N) ?$' ; DTMSG: DB CR,LF DB CR,LF,' --> REMOTE CONSOLE DRIVERS ARE DETACHED !!' CRLF: DB CR,LF,'$' ; EMSG1: DB CR,LF,07,' *** INVALID "ABOVE" ADDRESS SPECIFIED ***' DB CR,LF,'$' ; EMSG2: DB CR,LF,07,' *** "ABOVE" ADDRESS IS TOO SMALL ***' DB CR,LF,'$' ; ATMSG: DB CR,LF,' --- REMOTE CONSOLE DRIVERS ATTACHED AT $' ; ATMSG1: DB 'H ---',CR,LF,'$' ; CMSG: DB ' ^C',CR,LF,'$' ; ; --- BUFFERS --- ; CHPTR: DS 2 ; BUFFER POINTER FOR HEXIN ROUTINE LDADDR: DS 2 ; BUFFER FOR SAVING DRIVER LOAD ADDRESS OFFSET: DS 2 ; BUFFER FOR SAVING ADDRESS OFFSET CDPTR: DS 2 ; BUFFER FOR POINTER TO JUMP TABLE IN DRIVER ABOVE: DS 1 ; FLAG FOR "ABOVE" OR "BELOW" MODE ; ; --------------------------------------------------------------- ; ---- REMOTE CONSOLE DRIVERS ---- ; ; THIS SECTION GETS RELOCATED AND COPIED UP TO THE "TOP" ; OF AVAILABLE MEMORY. ANY ADDRESSES IN THIS CODE THAT ; NEED RELOCATION MUST BE REFERENCED IN THE RELOCATION TABLE. ; BDJ: JMP $-$ ; THIS GETS PATCHED ; ; --- COPY OF ORIGINAL CP/M JUMP TABLE ; OWBOOT: JMP $-$ ; COPY OF OLD WARM BOOT OCNST: JMP $-$ OCNIN: JMP $-$ OCNOUT: JMP $-$ ; ; --- NEW JUMP TABLE TO BE COPIED INTO CP/M JUMP TABLE --- ; NWBOOT: JMP WBOOT NCNST: JMP MCNST JMP MCNIN JMP MCNOUT ; ; --- FAKE WARM BOOT ROUTINE USED IN "BELOW" MODE --- ; WBOOT: LXI SP,0FFH MVI A,(JMP) STA 0 ; SET JUMP OPCODE AT 0000H BIOS3 EQU $+1 LXI H,$-$ SHLD 1 ; SET BIOS+3 WARM BOOT ADDRESS STA 5 PTX0: LXI H,BDJ SHLD 6 LXI B,80H ; SET DEFAULT DMA ADDRESS STDMA EQU $+1 CALL $-$ LDA CDISC ; GET DEFAULT DRIVE # MOV C,A CCP3 EQU $+1 JMP $-$ ; RE-ENTER CCP AT CCP+3 ; ; THE FOLLOWING 10 BYTES MUST NOT BE CHANGED OR MOVED ; TMSG: DB 'REMOTE C' ; IDENTIFIER STRING PTX00: DW OWBOOT ; POINT TO SAVED OLD JUMP TABLE ; ; --- NEW CONSOLE STATUS ROUTINE --- ; MCNST: CALL OCNST ; SEE IF STD CONSOLE HAS A CHAR. ORA A RNZ ; RETURN IF IT DOES PTX1: JMP MXISTAT ; OTHERWISE, CHECK MODEM DRIVER ; ; --- NEW CONSOLE INPUT ROUTINE --- ; MCNIN: CALL OCNST ; IS CHAR. AVAIL. FROM STD CONSOLE? ORA A PTX2: JNZ OCNIN ; YES, SO GO GET IT PTX3: CALL MXISTAT ; NO, SO TRY MODEM ORA A PTX4: JZ MCNIN ; IF NO CHAR., KEEP LOOKING PTX41: CALL MXIN ; GET CHAR. ORA A ; IS IT A NULL? PTX5: JZ MCNIN ; YES, IGNORE IT ANI 7FH ; MASK PARITY RET ; ; --- NEW CONSOLE OUTPUT ROUTINE --- ; MCNOUT: PUSH B ; SAVE OUTPUT CHAR. PTX6: CALL OCNOUT ; SEND IT TO STD CONSOLE POP B PTX7: JMP MXOUT ; SEND IT TO REMOTE CONSOLE ALSO ; ; ----- HARDWARE DEPENDENT I/O DRIVER ---- ; ------------------------------------- ; THE ORIGINAL VERSION FOR THE OSBORNE ; IS COMPLICATED BY A DESIGN FLAW ; IN THE RS232 PORT HARDWARE. WHEN ; NO CONNECTIONS ARE MADE, UART IS ; BEING GIVEN NULLS. ; ------------------------------------- ; MODCTLP EQU 00EAH ;PUT YOUR MODEM CONTROL PORT HERE MODSNDB EQU 40H ;YOUR BIT TO TEST FOR SEND MODSNDR EQU 40H ;YOUR VALUE WHEN READY MODRCVB EQU 80H ;YOUR BIT TO TEST FOR RECEIVE MODRCVR EQU 80H ;YOUR VALUE WHEN READY MODDATP EQU 00EBH ;YOUR MODEM DATA PORT ; these are setup for TRS-80 III serial WD TR1602 UART+ (G.P. & S.B.) ; Running Under Holmes Engineering VID-80 (tm)(c) CP/M 2.22J ; ; --- ALL OF THE MODEM ROUTINES MAY ONLY CHANGE --- ; THE A-REGISTER AND THE FLAGS. NO OTHER ; REGISTERS MAY BE CHANGED. ; ; --- INPUT DATA FROM MODEM --- ; MXIN: LXI H,CHRSAV ; POINT TO CHAR. BUFFER MOV A,M ; GET CHAR. MVI M,0 ; INDICATE CHAR. RECEIVED RET ; ; --- OUTPUT DATA TO MODEM --- ; MXOUT DI IN MODCTLP EI ANI MODSNDB CPI MODSNDR DVX1: JNZ MXOUT MOV A,C DI OUT MODDATP EI RET ; ; --- TEST IF DATA IS AVAILABLE FROM MODEM --- ; ; MXISTAT: DI IN MODCTLP EI ANI MODRCVB CPI MODRCVR ; DVX2: LDA CHRSAV ; GET POSSIBLE SAVE CHAR. DVX3: JNZ MXI1 ; IF NO CHAR., TEST BUFFER FOR ONE ; DI ; IF CHAR., GET IT IN MODDATP ; GET DATA EI ; DVX4: STA CHRSAV ; SAVE IT MXI1: ORA A ; WAS IT A NULL? RZ ; YES, SO RETURN NOT READY STATUS MVI A,0FFH ; SET READY STATUS RET ; CHRSAV: DB 0 ; BUFFER FOR ONE CHAR. ; ; --- INIT MODEM ROUTINES (NOT HARDWARE) --- ; THIS ROUTINE NEED NOT PRESERVE ANY ; OF THE REGISTERS. ; ;MXINIT EQU $ ;deleted following code, jw ; ; MVI C,56H ; USE 56H FOR 300 BAUD, 55H FOR 1200 ; LHLD 1 ; MVI L,3CH ; SETUP SPECIAL OSBORNE JUMP ; PCHL ; LENC EQU $-BDJ ; LENGTH OF CODE MODULE TO COPY UP ; ------------------------------------------------------ ; DS 80 STACK EQU $ END