; MXO13PX8 MEX overlay for Epson PX-8 Oct 18. 1985 ; ; (delete the ";" in the above title line if assembling with MAC) ; ; REV EQU 12 ; Overlay revision level ; ; MEX overlay for Epson PX-8 with MFU, Direct Connect modem, or external ; modem. Support is provided for an external dialing overlay such as ; MXO-SM13.ASM. For details see MXO-PX8.DOC. ; ; Written 3/10/85 by David B. Kozinn ; ; Copyright (C) 1985 by David B. Kozinn ; ; This program (in source or object code form) may be copied and distri- ; buted for non-commercial purposes. Sale of this program is forbidden ; without written consent of the author. ; ; The author can be contacted on CompuServe [76703,565] via Easyplex, or ; (preferably) in CP-MIG (PCS-47) or EpsOnline (PCS-19). ; ; PLEASE READ THE FOLLOWING IF YOU INTEND TO MODIFY THIS OVERLAY: ; --------------------------------------------------------------- ; Much of the commentary has been removed in order to save space. For ; complete documentation of how an overlay is structured, see the origi- ; nal overlay, MXO-PM.ASM, written by Ron Fowler. Please be sure to ; read the comments in that overlay if you intend to change this one. ; ; Version Date Changes ; ------- ------- ------- ; 1.2 870502 Fixed another bug in the SET COMM command that ; kept the uart from being properly set when using ; the internal modem. Also added pulse dial capa- ; bility. Removed all references to the letters ; A-D in the tone dialing area to make room. ; - Bob Kitchen ; ; 1.1 870301 Fixed bugs in the SET COMM command so that the ; correct values for "even" parity and "2" stop ; bits were sent to the RS-232 device. Also fixed ; the problem with the screen not keeping up when ; running at 1200 baud. ; - Bob Kitchen ; ; 1.0 850310 First general release version ; ;----------------------------------------------------------------------- ; ; Misc equates ; NO EQU 0 YES EQU 0FFH ; ; TPA EQU 100H CR EQU 13 LF EQU 10 TAB EQU 9 BELL EQU 7 ESC EQU 01BH CUROFF EQU 032H CURON EQU 033H XON EQU 011H XOFF EQU 013H ; ; PX-8 port definitions ; MCTLR2 EQU 002H ; Misc control signals (output) CCR EQU 00DH ; 8251 command port DCRREG EQU 084H ; Modem tone dialer control port (output) OCR EQU 085H ; Modem control register (output) STR EQU 086H ; Modem status register (input) OMR EQU 087H ; Modem port setup (output) ; ; PX-8 Special locations (see code for use) ; WBLOC EQU 0EC03H ; BIOS call Warm Boot location WRSDAT EQU 0F6A9H ; Working RS-232 data CTLR1 EQU 0F0B0H ; CTLR1 register value CTLR2 EQU 0F0B2H ; CTLR2 register value RSMODE EQU 0F6D0H ; 8251 Mode byte location RSCMD EQU 0F6D1H ; 8251 Command byte location RSOPN EQU 0F2C8H ; RS-232 open flag (00=Open) SLVFLG EQU 0F358H ; Slave cpu (6301) flag INTBUF EQU 0FB90H ; Internal rs232 buffer INTBUFL EQU 0160H ; Internal buffer length ; ; Bit definitions ; MDMINIT EQU 089H ; 8251 initialization string BRKBIT EQU 008H ; 8251 bit to turn break on MDRCVB EQU 001H ; Modem receive bits MDRCVR EQU 001H ; Modem recieve ready MDSNDB EQU 002H ; Modem send bits MDSNDR EQU 002H ; Modem recieve ready USEINT EQU 020H ; Set to 0, send this to CTLR2 to use int. DCD EQU 008H ; Use with RSIOX CTLIN ; ; Bit definitions for OCR ; OHC EQU 001H ; Off hook HSC EQU 002H ; Handset control MON EQU 004H ; Enable speaker TXC EQU 008H ; Transmit carrier ANS EQU 010H ; Answer mode TEST EQU 020H ; Test function PWR EQU 040H ; Modem Power CCT EQU 080H ; Connect to phone lne ; ; Bit definitions for STR ; BDS EQU 001H ; Bell Detect Signal. 0 if ringing CTSMSK EQU 004H ; Clear to send. (carrier det) =0 if clear MII EQU 080H ; Modem Installation Indicator 0=installed ; ; Special BIOS call locations ; CONIN EQU WBLOC+006H ; Direct console input CONOUT EQU WBLOC+009H ; Direct console output RSOPEN EQU WBLOC+039H ; Open RS-232 port RSCLOSE EQU WBLOC+03CH ; Close RS-232 port RSINST EQU WBLOC+03FH ; Check for input RSOUTST EQU WBLOC+042H ; Check for output RSIN EQU WBLOC+045H ; Get a character RSOUT EQU WBLOC+048H ; Send a character RSIOX EQU WBLOC+051H ; Special RS-232 calls SLAVE EQU WBLOC+072H ; Use slave CPU ; ; Equates for use with RSIOX ; OPNIOX EQU 010H ; Open using RSIOX CLSIOX EQU 020H ; Close using RSIOX INSTS EQU 030H ; Check for data in recieve buffer CTLIN EQU 070H ; Check carrier & DSR ; ; MEX locations ; QUEUE EQU 00D51H ; Queued I/O variable MODE EQU 00D54H ; Terminal mode byte (01 = in terminal mode) SMART EQU 00B00H ; Entry point for smart modem overlay ; ; Other equates ; WTCTS EQU 125 ; How long to wait for carrier. 125=25 seconds ; ; MEX service processor stuff ; MEX EQU 0D00H ; Address of the service processor INMDM EQU 255 ; Get char from port to A, CY=no more in 100 ms TIMER EQU 254 ; Delay 100ms * reg B TMDINP EQU 253 ; B=# secs to wait for char, cy=no char CHEKCC EQU 252 ; Check for ^C from KBD, Z=present SNDRDY EQU 251 ; Test for modem-send ready RCVRDY EQU 250 ; Test for modem-receive ready SNDCHR EQU 249 ; Send a character to the modem (after sndrdy) RCVCHR EQU 248 ; Recv a char from modem (after rcvrdy) LOOKUP EQU 247 ; Table search: see CMDTBL comments for info PARSFN EQU 246 ; Parse filename from input stream BDPARS EQU 245 ; Parse baud-rate from input stream SBLANK EQU 244 ; Scan input stream to next non-blank EVALA EQU 243 ; Evaluate numeric from input stream LKAHED EQU 242 ; Get nxt char w/o removing from input GNC EQU 241 ; Get char from input, cy=1 if none ILP EQU 240 ; Inline print DECOUT EQU 239 ; Decimal output PRBAUD EQU 238 ; Print baud rate ; NOSMART EQU NO ; Yes=no Smartmodem dialing overlay ; PRINT EQU 9 ; Simulated BDOS function 9: print string INBUF EQU 10 ; Input buffer, same structure as BDOS 10 ; IF NOSMART ORG SMART ; Put code in in case he calls Smartmodem CPI 255 ; without installing the overlay first RNZ ; Only do it once, at the end CALL ILPRT DB '** You have not installed a dialing overlay **' DB BELL,CR,LF,0 XRA A ; Set zero flag MVI A,3 ; Tell him dialing has been aborted RET ENDIF ; ; ORG TPA ; We begin ; ; DS 3 ; MEX has a JMP START here ; ; The following variables are located at the beginning of the program to ; facilitate modification without the need of re-assembly. ; PMODEM: DB NO ; Yes=PMMI modem \ / These 2 locations are not SMODEM: DB NO ; Yes=Smartmodem / \ referenced by MEX TPULSE: DB 'T' ; T=tone, P=pulse (tone or pulse dial flag) CLOCK: DB 28 ; Clock speed x .1, up to 25.5 mhz. MSPEED: DB 1 ; Sets display time for sending a file ; 0=110 1=300 2=450 3=600 4=710 ; 5=1200 6=2400 7=4800 8=9600 9=19200 BYTDLY: DB 1 ; Default time to send character in ; Terminal mode file transfer (0-9) ; 0=0 delay, 1=10 ms, 5=50 ms, 9=90 ms CRDLY: DB 1 ; End-of-line delay after CRLF in terminal ; Mode file transfer for slow BBS systems ; 0=0 delay, 1=100 ms, 5=500 ms, 9=900 ms COLUMS: DB 5 ; Number of directory columns SETFL: DB YES ; Yes=user-defined SET command SCRTST: DB YES ; Yes=if home cursor and clear screen ; Routine at CLRSCRN DB 0 ; Was once ACKNAK, now spare BAKFLG: DB YES ; Yes=make .BAK file CRCDFL: DB YES ; Yes=default to CRC checking ; No=default to Checksum checking TOGCRC: DB YES ; Yes=allow toggling of Checksum to CRC CVTBS: DB NO ; Yes=convert backspace to rub TOGLBK: DB YES ; Yes=allow toggling of bksp to rub ADDLF: DB NO ; No=no LF after CR to send file in ; Terminal mode (added by remote echo) TOGLF: DB YES ; Yes=allow toggling of LF after CR TRNLOG: DB NO ; Yes=allow transmission of logon ; Write logon sequence at location LOGON SAVCCP: DB YES ; Yes=do not overwrite CCP LOCNXT: DB NO ; Yes=local cmd if EXTCHR precedes ; No=not local cmd if EXTCHR precedes TOGLOC: DB YES ; Yes=allow toggling of LOCNXTCHR LSTTST: DB YES ; Yes=allow toggling of printer on/off ; In terminal mode. Set to no if using ; The printer port for the modem XOFTST: DB YES ; Yes=allow testing of XOFF from remote ; While sending a file in terminal mode XONWT: DB NO ; Yes=wait for XON after sending CR while ; Transmitting a file in terminal mode TOGXOF: DB YES ; Yes=allow toggling of XOFF testing IGNCTL: DB NO ; Yes=do not send control characters ; Above CTL-M to CRT in terminal mode ; No=send any incoming CTL-char to CRT EXTRA1: DB 0 ; For future expansion EXTRA2: DB 0 ; For future expansion BRKCHR: DB '@'-40H ; ^@ = Send a 300 ms. break tone NOCONN: DB 'N'-40H ; ^N = Disconnect from phone line LOGCHR: DB 'L'-40H ; ^L = Send logon LSTCHR: DB 'P'-40H ; ^P = Toggle printer UNSVCH: DB 'R'-40H ; ^R = Close input text buffer TRNCHR: DB 'T'-40H ; ^T = Transmit file to remote SAVCHR: DB 'Y'-40H ; ^Y = Open input text buffer EXTCHR: DB '^'-40H ; ^^ = Send next character ; ; The next two are for PMMI, we don't use them, but they have to hang ; around anyway. ; DB 250 DB 0 ; ; Low-level modem I/O routines ; INCTL1: JMP MODSTAT ; In modem control port DB 0,0,0,0,0,0,0 ; Spares ; OTDATA: JMP MODOUT ; Out modem data port DB 0,0,0,0,0,0,0 ; Spares ; INPORT: JMP MODIN ; In modem data port DB 0,0,0,0,0,0,0 ; Spares ; ; Bit-test routines ; MASKR: ANI MDRCVB ! RET ; Bit to test for receive ready TESTR: CPI MDRCVR ! RET ; Value of receive bit when ready MASKS: ANI MDSNDB ! RET ; Bit to test for send ready TESTS: CPI MDSNDR ! RET ; Value of send bit when ready ; ; ; Unused area: was once used for special PMMI functions, now used only ; to retain compatibility with MDM overlays. You may use this area for ; any miscellaneous storage you'd like but the length of the area *must* ; be 12 bytes. ; DS 12 ; ; Special modem function table ; LOGON: DS 2 ; Needed for MDM compat, not ref'd by MEX DIALV: JMP PDIAL ; Dial digit in A (see info at PDIAL) DISCV: JMP PDISC ; Disconnect the modem GOODBV: DS 3 ; Called before exit to CP/M INMODV: JMP NITMOD ; Initialization. Called at cold-start NEWBDV: JMP PBAUD ; Set baud rate NOPARV: DS 3 ; Set modem for no-parity PARITV: DS 3 ; Set modem parity SETUPV: JMP SETCMD ; SET cmd: jump to a RET if you don't write SET SPMENV: DS 3 ; Not used with MEX VERSNV: JMP SYSVER ; Overlay's voice in the sign-on message BREAKV: JMP PBREAK ; Send a break ; ; Entry points here are for compatibility with MDM7 ; ILPRTV: DS 3 ; Replace with MEX function 9 INBUFV: DS 3 ; Replace with MEX function 10 ILCMPV: DS 3 ; Replace with table lookup funct. 247 INMDMV: DS 3 ; Replace with MEX function 255 NXSCRV: DS 3 ; Not supported by MEX (returns w/no action) TIMERV: DS 3 ; Replace with MEX function 254 ; ; Clear/screen and clear/end-of-screen. Each routine must use the full ; 9 bytes alloted (may be padded with nulls). ; CLREOS: LXI D,EOSMSG MVI C,PRINT CALL MEX RET ; CLS: LXI D,CLSMSG ; Null unless patched MVI C,PRINT CALL MEX RET ; XRA A ; Don't allow queued I/O (it interferes ; With the stuff we're doing) STA QUEUE ; Set to Queued I/O flag location ; ;----------------------------------------------------------------------- ; ; *** END OF FIXED FORMAT AREA *** ; ;----------------------------------------------------------------------- ; ; Modem initialization. First make sure that the dialing overlay ad- ; dress is correct (some overlays ORG the dial vector and stick a JMP ; B00 there.) We have to make sure that we get control first. Also, ; store away the current value in the DISCV address, because it might be ; the address of the dialing overlay disconnect vector. We'll use this ; to disconnect along with the regular disconnect code if an external ; modem is being used. Then, set up the default communications parame- ; ters. Then, if the port is already open, just return, else set up to ; use the built-in modem. ; NITMOD: LXI H,PDIAL ; Get address of our dialing routine SHLD DIALV+1 ; Store it as the address to jump to LHLD DISCV+1 ; Get address of disconnect vector SHLD SMDISCV+1 ; Save it in case it's needed LXI B,PDISC ; Get our disconnect routine address XRA A ; Clear carry flag DB 0EDH,042H ; SBC HL,BC If zero, then the same JZ NIT0 ; Don't do anything special DCR A ; Get 0FFH to store STA GOTDISC ; Indicate that we've got external disc LXI H,PDISC ; Get the address of our disconnect routine SHLD DISCV+1 ; Store it in the proper place ; NIT0: LXI H,WRSDAT ; Get working rs232 data LXI D,BAUDRATE LXI B,4 DB 0EDH,0B0H ; LDIR LDA BAUDRATE ; Find out what baud we're set to LXI H,BAUDTBL MVI B,0 ; NIT1: CMP M ; Do we match this table entry? JZ NIT2 ; Yes INX H INR B JMP NIT1 ; NIT2: MOV A,B ; Store the table entry locally STA MDMSPD CALL SMSPEED ; Set modem speed for time for xfer LDA RSOPN ; See if the port is already open ORA A RZ ; Don't do anything if so CALL RSOPEN ; Turn the port on CALL PWRON ; Try to turn the modem on IN STR ; Read status register ANI MII ; Is modem installed? JNZ OPENIT ; No, open the RS-232 port normally CALL STPORT ; Set up to use the direct connect LDA OCRVAL ; Turn off modem power to conserve ANI (NOT PWR) AND 0FFH STA OCRVAL OUT OCR MVI A,0FFH ; Indicate we're using the internal modem STA MDMTYPE RET ; OPENIT: CALL RSCLOSE ; Close the port to clean things up CALL RSOPEN ; Open it up for the regular port RET ; ; Send-break routine ; PBREAK: LDA RSCMD ; Get the current command for the 8251 ORI BRKBIT ; Turn break on OUT CCR ; Send it to the 8251 MVI B,3 ; Wait 300 ms MVI C,TIMER CALL MEX LDA RSCMD ; Restore the 8251 to normal OUT CCR RET ; ; Disconnect the modem ; PDISC: LDA MDMTYPE ; See if we're using an external modem ORA A ; This will be zero if so JNZ PDISC0 ; If not, don't worry about it LDA GOTDISC ; See if we had an external routine ORA A ; This will be non-zero if so JNZ SMDISCV ; Call it if it's there ; PDISC0: CALL RSCLOSE LDA OCRVAL ; Get current modem control values ANI 0FFH-(CCT+TXC+OHC) ; On-hook, carrier off,disconnect OUT OCR ; Send it ANI (NOT PWR) AND 0FFH ; Now turn power off too OUT OCR STA OCRVAL ; Save this as current mod. ctl. value CALL RESPORT ; Reset to use internal CALL SPKROFF ; Turn the speaker off CALL RSOPEN RET ; ; External dialing routine disconnect code is called through here. ; SMDISCV:JMP PDISC ; <-----This may be modified ; ;----------------------------------------------------------------------- ; ; DIALING ROUTINES ; ; The DIGITS table is a translation for digit to register value for all ; of the supported tone digits. The modem also understands that a com- ; ma (,) means to wait for n seconds before continuing (for compatabil- ; ity with various intelligent modems). Any other values (such as -, ; (, or ) ) are ignored. For pulse dialing, only the digits 0-9 are ; used, all else, except a comma, is ignored. ; DIGITS: DB 1DH,10H,11H,12H ; 0, 1, 2, 3 DB 14H,15H,16H,18H ; 4, 5, 6, 7 DB 19H,1AH ; 8, 9 ; SPLAT: DB 1CH ; * ; CRUNCH: DB 1EH ; # ; PDIAL: MOV B,A ; Save the digit LDA MDMTYPE ; See if we're using an external modem ORA A MOV A,B ; Restore the digit JZ SMART ; If so, jump to the Hayes routines CPI 254 ; Start-dial? JZ STDIAL CPI 255 ; End-dial JZ ENDIAL CPI ',' ; Smartmodem pause command JNZ CKDIG ; If not pause, continue LDA COMDLY ; Delay n seconds MOV B,A ADD A ; X 2 ADD A ; X 4 ADD A ; X 8 ADD B ; X 9 ADD B ; X 10 MOV B,A MVI C,TIMER CALL MEX RET ; CKDIG: CPI '9'+1 ; Digits are 0-9 RNC ; Too big...return SUI '0' JC CKSPEC ; Too small....check if it's * or # PUSH A LDA TPULSE ; Check to see if tone or pulse CPI 'P' JZ PUDIAL ; Go to pulse dial routines POP A LXI H,DIGITS ; Get start of digits table JMP DIALIT ; CKSPEC: LXI H,SPLAT ; Check for specials CPI ('*'-'0') AND 0FFH ; Is it *? JZ DIALIT1 ; Yup, go dial INX H ; Point to CRUNCH CPI ('#'-'0') AND 0FFH ; Is it #? RNZ ; No, forget it JMP DIALIT1 ; Yup, go dial ; ; First get the value to send to the tone control register. At DIALIT, ; HL contains the proper table, and A contains the offset into that table. ; DIALIT: MVI B,0 MOV C,A ; Get offset into BC DAD B ; Get real byte location into HL ; DIALIT1:LDA TPULSE ; Check for tone or pulse CPI 'P' RZ ; Return if pulse MOV A,M ; Get value to dial into A OUT DCRREG ; Start sending the tone MVI B,1 ; Send it for 100ms (which is kinda long MVI C,TIMER ; But it's easier than coding my own timing CALL MEX ; Routine.) XRA A OUT DCRREG ; Turn tone off MVI B,1 ; Wait for 100ms for the inter-digit delay MVI C,TIMER CALL MEX RET ; ; Pulse dialing routines (one pulse is 60ms onhook followed by 40ms off- ; hook). ; PUDIAL: POP A CPI 0 JNZ PUDIAL1 ; Jump if not equal to zero MVI A,0AH ; 0 is 10 for pulse dialing ; PUDIAL1:CALL ST60 ; Onhook for 60ms CALL ST40 ; Offhook for 40ms DCR A CPI 0 JNZ PUDIAL1 ; Repeat per value of each digit MVI B,7 ; 700ms between digits MVI C,TIMER CALL MEX RET ; STDEL: DCX B ; Time delay subroutine for MOV A,B ; Producing the correct pulse ORA C ; Lengths JNZ STDEL RET ; ST60: PUSH A LDA OCRVAL ; Connect to phone, offhook, speaker on ANI (NOT OHC) AND 0FFH ; Onhook OUT OCR LXI B,6000 ; 60ms onhook CALL STDEL POP A RET ; ST40: PUSH A LDA OCRVAL ; Connect to phone, offhook, speaker on OUT OCR LXI B,4000 ; 40ms offhook CALL STDEL POP A RET ; ; Start-dial sequence: Go thru normal init sequence, assuming that the ; guy is not trying to dial while connected. (This should disconnect ; him anyway). ; STDIAL: CALL PDISC ; Disconnect LDA OCRVAL ; Turn on monitor soon ORI MON STA OCRVAL CALL RESPORT ; I don't know why, but I gotta do this CALL PWRON ; Init modem and ports CALL SPKRON ; Turn power to speaker on LDA OCRVAL ; Get current value for OCR ANI (NOT ANS) AND 0FFH ; Set originate mode STA OCRVAL OUT OCR OFFHK: LDA OCRVAL ; Have to reload 'cause we're called directly ORI CCT ; Connect to phone OUT OCR ORI OHC ; Go off hook OUT OCR STA OCRVAL MVI B,20 ; Wait 2 seconds for dial tone MVI C,TIMER CALL MEX RET ; Dialing init done ; ; End-dial sequence: Watch to see if CTS goes on within 50 seconds. If ; so, turn on carrier, turn speaker off, and connect to the line. ; ENDIAL: LDA OCRVAL ; Turn on carrier ORI TXC OUT OCR STA OCRVAL CALL STPORT MVI E,WTCTS ; # of ms * 5 to wait ; LP1: MVI B,2 ; 200 ms. MVI C,TIMER CALL MEX IN STR ; Check modem status register ANI CTSMSK ; See if we've got carrier yet JZ GOTCAR ; If it's zero, then we've got carrier MVI C,CHEKCC ; Not yet, see if he hit ctl-c CALL MEX MVI A,3 ; Get ready to return code JZ NOCAR ; Yup, return DCR E ; Nope, count down JNZ LP1 ; Keep going if more time MVI A,2 ; Set code in A to 2 (no answer) ; NOCAR: PUSH PSW ; Save the return code CALL PDISC ; Hang up POP PSW ; Get the return code back RET ; ; GOTCAR - Come here to go on-line, we've got a carrier from remote ; GOTCAR: CALL SPKROFF ; Turn the speaker off XRA A ; Report that we got carrier RET ; ; ;----------------------------------------------------------------------- ; PBAUD: RET ; Use SET COMM for this ; ; Sign-on message ; SYSVER: LXI D,SOMESG MVI C,PRINT CALL MEX RET ; SOMESG: DB 'Epson PX-8 overlay V' DB REV/10+'0' DB '.' DB REV MOD 10+'0' DB CR,LF,'$' ; ; Input from the status port. Since the PX-8 has 2 status ports, and ; we can't tell why we're being call (for input or output), we have to ; kludge here. We'll call both in & out status, and fake a 1 byte sta- ; tus word. See the MOD??? bytes for the values. Also, we check here ; to see if carrier has been lost (only if we were using the modem.) If ; so, then we'll disconnect from the phone line, reset the port and tell ; the user. ; ; NOTE: There is really no need for output status, so ; these routines always return "ready to output". ; However, the basic code structure to support ; both input and output status has been left in ; should it ever be necessary. ; ; Automatic X-ON/X-OFF flow control is also done from this point. ; ; NOTE: For the automatic X-ON/X-OFF flow control to ; work properly, ASIZE: must be set to 255h at ; memory location 0D22h. If not, use MEXPAT.ASM ; to reset the buffers. ; MODSTAT:PUSH B ; Push all registers (except A) PUSH D PUSH H LDA CTLR2 ; See if we're using an MFU ANI USEINT JNZ MDSTAT1 ; If not, forget about it IN STR ; Else check modem status register ANI CTSMSK JZ MDSTAT1 ; Everything Ok if it's there CALL PDISC ; Otherwise hang up CALL ILPRT ; And say something about it DB CR,LF,'** Carrier Lost **',BELL,CR,LF,0 ; MDSTAT1:LDA MODE ; Get terminal mode CPI 1 ; 01 means in terminal mode JNZ MDSTAT4 ; If not, then don't worry about it ; MDSTAT2:MVI B,INSTS ; Check for characters in input buffer LXI H,WIPEOUT ; Here's where to put the returned info CALL RSIOX JNZ MDSTAT2 ; Wait until we get good status XRA A ; Clear carry LXI H,200 ; 3/4 full buffer DB 0EDH,042H ; SBC HL,BC JNC MDSTAT3 ; Continue if < 200 chars in buffer LDA PENDXOFF ; Is there an XOFF outstanding already? ORA A ; It'll be 0 if not JNZ MDSTAT4 ; If so, then just go ahead MVI C,XOFF ; Send out an XOFF CALL RSOUT XRA A DCR A STA PENDXOFF ; Indicate a pending XOFF JMP MDSTAT4 ; Continue ; MDSTAT3:MVI B,INSTS ; Check input again, this time we're LXI H,WIPEOUT ; Seeing if it's time to send an XON CALL RSIOX JNZ MDSTAT3 XRA A LXI H,50 DB 0EDH,042H ; SBC HL,BC JC MDSTAT4 ; Don't send XON until < 50 chars in buffer LDA PENDXOFF ; Ok, we've got < 50, did we send an XOFF? ORA A JZ MDSTAT4 ; No, so don't do anything MVI C,XON CALL RSOUT ; Send the XON XRA A STA PENDXOFF ; MDSTAT4:CALL RSINST ; Now get status ANI MDRCVB ; Mask off what we don't care about ORI MDSNDB ; Always say that output is ready ; POPEM: POP H POP D POP B RET ; ; Get a character ; MODIN: PUSH B PUSH D PUSH H MVI B,INSTS LXI H,STATBLK CALL RSIOX ; Make sure there is really data so we ORA A ; Don't ever hang waiting JZ MODIN1 CALL RSIN ; MODIN1: POP H POP D POP B RET ; ; Send a character ; MODOUT: PUSH B PUSH D PUSH H MOV C,A CALL RSOUT POP H POP D POP B RET ; ; Type character in A on console ; TYPE: PUSH H ; Save 'em PUSH D PUSH B MOV C,A ; Align output character CALL CONOUT POP B POP D POP H RET ; ; SETPORT - set up to use internal modem ; STPORT: LDA CTLR2 ; Get current port info ANI (NOT USEINT) AND 0FFH ; Use internal modem ; SPORT: STA CTLR2 OUT MCTLR2 RET ; ; RESPORT - set up to use external modem ; RESPORT:LDA CTLR2 ; Get current port info ORI USEINT ; Use external modem JMP SPORT ; Store & send to modem ; ; PWRON - Turn power on to the modem (& some other initialization stuff) ; PWRON: MVI A,MDMINIT ; Initialize the 7508 OUT OMR LDA OCRVAL ; Get current parameters ORI PWR ; Turn the power on OUT OCR STA OCRVAL ; Save the parameters MVI B,1 ; Wait a while to let things settle MVI C,TIMER CALL MEX RET ; ; SPKRON - Turn the speaker on ; SPKRON: MVI A,0FFH STA SLVFLG LXI D,SLVPRAM1 CALL SLAVE RET ; ; SPKROFF - Turn speaker off ; SPKROFF:LDA OCRVAL ; Get current params ANI (NOT MON) AND 0FFH ; We're not monitoring anymore OUT OCR STA OCRVAL MVI A,0FFH STA SLVFLG LXI D,SLVPRAM2 CALL SLAVE RET ; ; Print in-line message ... blows away C register ; ILPRT: MVI C,ILP ; Get function code JMP MEX ; Go do it ; ; PLACECUR - Place cursor at row/col specified by BC. ; PLACECUR: PUSH PSW MOV A,B ADI 01FH ; Add in offset STA ROW MOV A,C ADI 01FH ; Add in offset STA COL CALL ILPRT DB ESC,'=' ; ROW: DS 1 ; COL: DS 1 DB 0 POP PSW RET ; ; Keyin - get a character into A ; KEYIN: PUSH B PUSH D PUSH H CALL CONIN ; Direct console input POP H POP D POP B RET ; ; UCASE - Convert character in A to uppercase ; UCASE: CPI 'a' RC ; Return if not lower case CPI 'z'+1 RNC ; Return if > lower case z ANI 05FH ; Else change to upper case RET ; ; SMSPEED - Set time to transfer speed ; SMSPEED:LDA MDMSPD ; Get locally stored speed value MOV C,A ; Put in lower half of BC MVI B,0 ; Zap upper half of BC LXI H,XSPDTBL ; Get address of xfer speed table DAD B ; Get address of time for xfer byte MOV A,M ; Get the value STA MSPEED ; Store it RET ; ; Data area ; ; ; XSPDTBL - transfer speed table. The number in parenthesis is the value ; given to MEX. This differs from the actual baud rate in ; some cases due to the baud rates available on the PX-8. ; XSPDTBL: DB 0 ; Unused DB 0 ; 110 Baud (110) DB 0 ; 150 Baud (110) DB 1 ; 300 Baud (300) DB 3 ; 800 Baud (600) DB 5 ; 1200 Baud (1200) DB 6 ; 2400 Baud (2400) DB 7 ; 4800 Baud (4800) DB 8 ; 9600 Baud (9600) DB 9 ; 19200 Baud (19200) ; EOSMSG: DB ESC,'Y','$' ; Clear to end-of-screen CLSMSG: DB ESC,'*','$' ; Clear whole screen OCRVAL: DB 0 ; OCR register value MDMTYPE: DB 0 ; Modem type, 0FFH=external, 0=internal GOTDISC: DB 0 ; Got external disconnect routine, FF=Yes MDMSPD: DS 1 ; Current port speed COMDLY: DB 2 ; #secs to wait for , in dial string PENDXOFF: DB 0 ; 0FFH if XOFF pending, 0 otherwise STATBLK: DS 9 ; Returned info from RSIOX INSTS call ; ;--------------------Start of slave CPU data---------------------------- ; ; The following group of data items are for using the slave CPU. ; ; DO NOT ADD OR REMOVE ANYTHING IN THIS AREA!!! ; SLVPRAM1: DW ONSNDCMD DW ONSNDLEN DW ONRETVAL DW ONRETLEN ; ONSNDCMD: DB 072H,080H ONSNDLEN: DB 2 ONRETVAL: DB 1 ONRETLEN: DB 1 SLVPRAM2: DW OFFSDCMD DW OFFSDLEN DW OFFRTVAL DW OFFRTLEN OFFSDCMD: DB 072H,0 OFFSDLEN: DB 2 OFFRTVAL: DB 1 OFFRTLEN: DB 1 ; ;--------------------End of Slave CPU data------------------------------ ; ; Control is passed here after MEX parses a SET command. ; SETCMD: MVI C,SBLANK ; Any arguments? CALL MEX JC SETSHO ; If not, go print out values LXI D,CMDTBL ; Parse command CALL TSRCH ; From table PUSH H ; Any address on stack RNC ; If we have one, execute it POP H ; Nope, fix stack ; SETERR: LXI D,SETEMS ; Print error MVI C,PRINT CALL MEX RET ; SETEMS: DB CR,LF,'SET command error',CR,LF,'$' ; CMDTBL: DB '?'+80H ; "set ?" DW STHELP DB 'OFFHOO','K'+80H ; "set offhook" DW SETOFF DB 'COM','M'+80H ; "set comm" DW SETCOMM DB 'DELA','Y'+80H ; "set delay" DW SETDLY DB 'PULS','E'+80H ; "set pulse" DW SETPUL DB 0 ; <<=== table terminator ; ; SET : print current statistics ; SETSHO: CALL CARRSH ; Show carrier present/not present LXI H,SHOTBL ; Get table of SHOW subroutines ; SETSLP: MOV E,M ; Get table address INX H MOV D,M INX H MOV A,D ; End of table? ORA E RZ ; Exit if so PUSH H ; Save table pointer XCHG ; Adrs to HL CALL GOHL ; Do it MVI C,CHEKCC ; Check for console abort CALL MEX POP H ; It's done JNZ SETSLP ; Continue if no abort RET ; GOHL: PCHL ; ; table of SHOW subroutines ; SHOTBL: DW SHSEP DW SHHOOK DW SHDLY DW SHPUL DW SHSEP DW 0 ; <<== table terminator ; ; LF seperator ; SHSEP: CALL ILPRT DB CR,LF,0 RET ; ; SET ? processor ; STHELP: LXI D,HLPMSG MVI C,PRINT CALL MEX RET ; ; The help message ; HLPMSG: DB 0CH,'SET command, PX-8 version:',CR,LF DB CR,LF,'SET COMM set/display comm parameters' DB CR,LF,'SET DELAY n set delay for comma in dial string' DB CR,LF,'SET PULSE set pulse dialing' DB CR,LF,'SET OFFHOOK go offhook' DB CR,LF,LF,'$' ; ; Show carrier status ; CARRSH: CALL CARRCK ; Check for it LXI D,NOMESG ; Tell about carrier MVI C,PRINT CZ MEX ; Print the "NO" if no carrier LXI D,CARMSG ; Print "carrier present" MVI C,PRINT CALL MEX RET ; NOMESG: DB 'no $' CARMSG: DB 'carrier present',CR,LF,'$' ; ; Check the PX-8 for carrier-present (Z=no) ; CARRCK: MVI B,CTLIN ; Get status byte CALL RSIOX ANI DCD ; Check for carrier detect RET ; ; Set OFFHOOK processor ; SETOFF: CALL PDISC ; Disconnect if anything was there CALL PWRON ; Fire up the modem CALL OFFHK ; SHHOOK: CALL ILPRT DB 'modem is ',0 LDA OCRVAL ANI OHC JZ SHONHK CALL ILPRT DB 'off-hook',CR,LF,0 RET ; SHONHK: CALL ILPRT DB 'on-hook',CR,LF,0 RET ; ; Set delay for comma ; SETDLY: MVI C,EVALA ; Get the number CALL MEX MOV A,H ; Validate ORA A JNZ SETERR MOV A,L STA COMDLY ; Store new rate ; ; Show dialing delay ; SHDLY: CALL ILPRT DB 'delay time for dialing: ',0 LDA COMDLY MOV L,A MVI H,0 MVI C,DECOUT CALL MEX CALL ILPRT DB ' sec',CR,LF,0 RET ; ; Set for tone or pulse dialing ; SETPUL: MVI C,SBLANK ; Any arguments? CALL MEX JC PULSON ; If not, pulse on MVI A,'T' ; Tone dial flag STA TPULSE JMP SHPUL PULSON: MVI A,'P' ; Pulse dial flag STA TPULSE ; ; Show tone or pulse status ; SHPUL: CALL ILPRT DB 'dialing mode: ',0 LDA TPULSE CPI 'T' JZ SHPUL1 CALL ILPRT DB 'pulse',CR,LF,0 RET ; SHPUL1: CALL ILPRT DB 'tone',CR,LF,0 RET ; ; Compare next input-stream item in table @DE; CY=1 ; if not found, else HL=matched data item ; TSRCH: MVI C,LOOKUP ; Get function code JMP MEX ; Pass to MEX processor ; SETCOMM:CALL CLS ; Clear the screen LXI D,MENU MVI C,PRINT CALL MEX ; Display the setup menu ; ; Display current values on setup screen ; CALL DBAUD CALL DDBITS CALL DPARITY CALL DSTP CALL DMODEM ; ; Get user's response and set paramiters ; SETUP0: CALL KEYIN CALL UCASE CPI ESC JZ SETUP CPI '9'+1 ; Greater than baud selection JNC SDBITS ; Check for data bits CPI '1' ; Less than 1? JC SETUP0 ; Get another response ANI 0FH MOV E,A MVI A,10 SUB E STA MDMSPD MOV C,A MVI B,0 LXI H,BAUDTBL DAD B MOV A,M STA BAUDRATE CALL DBAUD JMP SETUP0 ; SDBITS: CPI 'B'+1 ; Greater than data bits JNC SPARITY ; Check for parity CPI 'A' ; Less than 'a' JC SETUP0 ; Get another response SUI 3FH ; Make 2 or 3 STA DBITS CALL DDBITS JMP SETUP0 ; SPARITY:CPI 'E'+1 ; Greater than parity JNC SSTOP ; Check for stop bits CPI 'E' ; Check for "even" parity JNZ SPAR0 SUI 'B' ; Even parity = 3 JMP SPAR1 ; SPAR0: SUI 'C' ; Make 0 or 1 ; SPAR1: STA PARBITS CALL DPARITY JMP SETUP0 ; SSTOP: CPI 'G'+1 ; Greater than stop bits JNC SMOD ; Check for modem SUI 'F'-1 CPI 1 JZ SSTOP1 ADI 1 ; Two stop bits = 3 ; SSTOP1: STA STP CALL DSTP JMP SETUP0 ; SMOD: CPI 'I'+1 ; Greater than baud JNC SETUP0 ; Bad selection get another response SUI 'H' JZ SMOD1 CALL PWRON ; Try to turn the modem on IN STR ; Read status register ANI MII ; Is modem installed? JNZ SMOD2 MVI A,0FFH ; SMOD1: STA MDMTYPE CALL DMODEM JMP SETUP0 ; SMOD2: MVI A,BELL CALL TYPE ; SMOD3: LXI B,0201H CALL PLACECUR CALL ILPRT DB TAB,'** NO MODEM **',0 XRA A STA MDMTYPE CALL DMODEM JMP SETUP0 ; ; Display baud rate ; DBAUD: LXI B,30DH CALL PLACECUR LXI H,BAUDSPD MVI D,0 LDA MDMSPD ; Get baud rate code CPI 0FFH RZ ; Unknown baud rate MOV E,A ; X1 ADD A ; X2 ADD A ; X4 ADD E ; X5 ADD E MOV E,A DAD D ; Point to correct rate XCHG MVI C,PRINT CALL MEX CALL ILPRT DB ' bps ',CR,LF,0 RET ; ; Display data bits ; DDBITS: LXI B,50DH CALL PLACECUR LDA DBITS CPI 2 MVI A,'7' JZ DDBITS1 MVI A,'8' ; DDBITS1:CALL TYPE RET ; ; Display parity ; DPARITY:LXI B,60DH CALL PLACECUR LDA PARBITS ORA A JNZ DPAR1 CALL ILPRT DB 'none',0 RET DPAR1: CPI 1 JNZ DPAR2 CALL ILPRT DB 'odd ',0 RET DPAR2: CALL ILPRT DB 'even',0 RET ; ; Display stop bits ; DSTP: LXI B,70DH CALL PLACECUR LDA STP CPI 1 MVI A,'1' JZ DSTP1 MVI A,'2' ; DSTP1: CALL TYPE RET ; ; Display modem type ; DMODEM: LXI B,80DH CALL PLACECUR LDA MDMTYPE ORA A JNZ DMODEM1 CALL ILPRT DB 'external',0 RET ; DMODEM1:CALL ILPRT DB 'internal',0 RET ; SETUP: CALL STPORT ; Set up for internal modem just in case CALL SMSPEED ; Set time to xfer speed LDA MDMTYPE ; See what kind of modem we're using INR A ; If FF, then it's internal JZ SETUP1 ; Yep, it's internal CALL RESPORT ; Using external, do setup ; SETUP1: LXI H,PARAMS ; Copy all settings to RSIOX string LXI D,WIPEOUT LXI B,9 DB 0EDH,0B0H ; LDIR LXI H,BAUDRATE ; Copy uart settings to working area LXI D,WRSDAT LXI B,4 DB 0EDH,0B0H ; LDIR MVI B,CLSIOX CALL RSIOX ; Close port first MVI B,OPNIOX LXI H,WIPEOUT CALL RSIOX ; Open with new parameters CALL CLS CALL ILPRT DB ESC,CURON DB CR,LF,LF,LF DB TAB,TAB,'Communication initialization completed',CR,LF DB LF,LF,0 RET ; BAUDSPD:DB '50 $110 $150 $300 $600 $' DB '1200 $2400 $4800 $9600 $19200$' ; BAUDTBL:DB 0FFH ; 50 baud not supported DB 2 ; 110 baud DB 4 ; 150 baud DB 6 ; 300 baud DB 8 ; 600 baud DB 0AH ; 1200 baud DB 0CH ; 2400 baud DB 0DH ; 4800 baud DB 0EH ; 9600 baud DB 0FH ; 19.2k baud ; MENU: DB ESC,CUROFF DB TAB,'Select alphanumeric or ESC to return',CR,LF,LF DB 'bit rate : 1=19200 2=9600 3=4800' DB ' 4=2400' DB ' 5=1200',CR,LF DB ' 6=600 7=300 8=150' DB ' 9=110',CR,LF DB 'data bits : A=7 B=8',CR,LF DB 'parity : C=none D=odd E=even' DB CR,LF DB 'stop bits : F=1 G=2',CR,LF DB 'modem type: H=external I=internal$' ; PARAMS: DW INTBUF DW INTBUFL BAUDRATE: DS 1 DBITS: DS 1 PARBITS: DS 1 STP: DS 1 SPECIAL: DB 0FFH ; Not XON/XOFF, not SI/SO, DTR on, RTS on ; WIPEOUT: DS 9 ; This area gets overwritten by BIOS call ; ;----------------------------------------------------------------------- ; ; End of PX-8 MEX modem overlay ; ;----------------------------------------------------------------------- ; END