TITLE System-dependent installation overlay for ZMP SUBTTL Author: Ron Murray ; System-dependent installation overlay for ZMP ; Author: Ron Murray ; Name ZMPOVH89.Z80 ; Dated Nov 11, 1988 ; Written by - Ron Murray, c/o Z-Node 62, 061-9-450-0200 ; Perth, Western Australia. ; Modified by - Ted May, 116B Laval St., Vanier, Ont., Canada ; (613)741-0862 ; for the H89-H19 terminal ; with a Hays compatable 2400 baud modem ; (US Robotics Courier 2400) ; 89/04/12 - Modified to ZMP v1.5 - George Conover ; Modified to ZMP v1.4 standard Ron Murray Nov 11, 88 ; Modified to ZMP v1.3 standard Ron Murray Oct 11, 88 ; Modified to ZMP v1.2 standard Ron Murray Sept 15, 88 ; ;----------------------------------------------------------------------- ; ; System-dependent code overlay for ZMODEM ; ; Insert your own code as necessary in this file. Code contained ; herein has been written in Z80 code for use with M80 or SLR programs. ; Assemble as follows: ; SLR ZMO-MH01/h ; MLOAD ZMP.COM=ZMODEM.COM,ZMO-MH01.HEX ; or ; M80 =ZMO-MH01.Z80 ; RELHEX ZMO-MH01 ; MLOAD ZMP.COM=ZMODEM.COM,ZMO-MH01.HEX ; (Don't use L80 without changing the source for assembly as a CSEG ; file.) ;----------------------------------------------------------------------- ; Code contained herein has been written in Z80 code for use with M80. ; Once assembled, convert to hex with RELHEX and use MLOAD to overlay it ; over the main ZMPX.COM file to produce your very own ZMP.COM. ;----------------------------------------------------------------------- ; Notes on modifying this file: ; Hi-Tech C requires that functions do not change either index register ; (IX or IY). If your overlay requires either of these to be changed, ensure ; they are restored to their original values on return. ; Since collecting parameters from C functions can be tricky, only change ; the parts marked 'Insert your own code here'. Do NOT modify the jump ; table at the start. Do NOT modify the entry/exit sections of each ; function. Do NOT pass 'GO'. Do NOT collect $200. ; Apart from defining modem functions, this file also defines terminal ; characteristics. Most have been set up for ADM-3A (with a few of my own ; additions). Modify to suit your own terminal. An inline print routine ; is provided for printing strings in the usual way: usage is ; CALL PRINT ; DEFB 'required string',0 ; Don't forget to set your clock speed at the clkspd variable. ; If you find your overlay exceeds the maximum size (currently 0400h), ; you will have to re-compile the whole thing. Good luck. You might try ; informing us if you need to do this: if too many people need to do it, we ; haven't allowed enough room. ; Ron Murray Aug 15, 88 ;----------------------------------------------------------------------- NO EQU 0 YES EQU NOT NO CLKSPD EQU 2 ; Processor clock speed in MHz DEBUG EQU NO ; To allow debugging of overlay with ; Z8E etc. ; Set the following two equates to the drive and user area which will ; contain ZMP's .OVR files, .CFG file, .FON file and .HLP file. Set ; both to zero (null) to locate them on the drive from which ZMP was ; invoked. OVERDRIVE EQU 0 ; Drive to find overlay files on ('A'-'P') OVERUSER EQU 0 ; User area to find files ;----------------------------------------------------------------------- ; NOT user-set variables USERDEF EQU 0145H ; Origin of this overlay. This address ; should not change with subsequent ; revisions. MSPEED EQU 003CH ; Location of current baud rate. OVSIZE EQU 0400H ; Maximum size of this overlay .Z80 ; use z80 code ASEG ; absolute IF DEBUG ORG 100H ; So you can debug it with CEBUG, ZSID, etc. ELSE ORG USERDEF ENDIF ESC EQU 1BH CTRLQ EQU 11H CR EQU 0DH LF EQU 0AH BDOS EQU 5 ; The following define the H8/89 SIO Modem Port addresses... DPORT EQU 0D8H ; Data port (base port) LSPDIV EQU DPORT ; LSP baud rate divisor if DLAB set IENREG EQU DPORT+1 ; Interupt Enable register MSPDIV EQU DPORT+1 ; MSP baud rate divisor if DLAB set IIDREG EQU DPORT+2 ; Interrupt identification register (r/o) LCPORT EQU DPORT+3 ; Line Control register MCPORT EQU DPORT+4 ; Modem Control register LSPORT EQU DPORT+5 ; Line Status register MSPORT EQU DPORT+6 ; Modem Status register ; Line Control (LCPORT) bits - - - - - - - - - - - - - - - - - WLS0 EQU 00000001B ; Word length select 0 WLS1 EQU 00000010B ; Word length select 1 STB EQU 00000100B ; Stop bit select PEN EQU 00001000B ; Parity Enable (0 for disabled) PES EQU 00010000B ; Even parity select (0 for odd) SPE EQU 00100000B ; Stick parity BRKS EQU 01000000B ; Break set (set break) DLAB EQU 10000000B ; Divisor Latch Access Bit ; Modem Control (MCPORT) bits - - - - - - - - - - - - - - - - - MCBASE EQU 00000000B ; Basic setup: no DTR or RTS DTR EQU 00000001B ; Data Terminal Ready RTS EQU 00000010B ; Request To Sent OUT1 EQU 00000100B ; Aux Output #1 OUT2 EQU 00001000B ; Aux Output #2 TSTLP EQU 00010000B ; Sets 8250 Test Loop condition ; Line Status (LSPORT) bits - - - - - - - - - - - - - - - - - - DAV EQU 00000001B ; Data Available (and bit to test) ORUN EQU 00000010B ; Overrun Error (rec'd was char overwritten RPERR EQU 00000100B ; Parity Error FERR EQU 00001000B ; Framing Error (checks for valid stop bit) BRKD EQU 00010000B ; Break Detect TBMT EQU 00100000B ; Transmit Buffer Empty (and bit to test) TSRE EQU 01000000B ; Transmit Shift Register Empty (r/o) ; Modem Status (MSPORT) bits - - - - - - - - - - - - - - - - - - DCTS EQU 00000001B ; Delta Clear To Send DDSR EQU 00000010B ; Delta Data Set Ready TERI EQU 00000100B ; Trailing Edge Ring Indicator DRLSD EQU 00001000B ; Delta Receive Line Signal Detect CTS EQU 00010000B ; Clear To Send DSR EQU 00100000B ; Data Set Ready RDET EQU 01000000B ; Ring Detect RLSD EQU 10000000B ; Carrier Detect RESET EQU 00000001B ; Output Reset Code ; Baud rate divisor values - - - - - - - - - - - - - - - - - - - BD110 EQU 1047 ; 110 bps BD300 EQU 384 ; 300 bps BD450 EQU 256 ; 450 bps BD600 EQU 192 ; 600 bps BD710 EQU 162 ; 710 bps BD1200 EQU 96 ; 1200 bps BD2400 EQU 48 ; 2400 bps BD4800 EQU 24 ; 4800 bps BD9600 EQU 12 ; 9600 bps BD19200 EQU 6 ; 19,200 bps BD38400 EQU 3 ; 38,400 bps BD57600 EQU 2 ; 57,600 bps ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;Jump table for the overlay: do NOT change this JUMPTAB: JP SCRNPR ; screen print JP MRD ; modem read with timeout JP MCHIN ; get a character from modem JP MCHOUT ; send a character to the modem JP MORDY ; test for tx buffer empty JP MIRDY ; test for character received JP SNDBRK ; send break JP CURSADD ; cursor addressing JP CLS ; clear screen JP INVON ; inverse video on JP INVOFF ; inverse video off JP HIDE ; hide cursor JP SHOW ; show cursor JP SAVECU ; save cursor position JP RESCU ; restore cursor position JP MINT ; service modem interrupt JP INVEC ; initialise interrupt vectors JP DINVEC ; de-initialise interrupt vectors JP MDMERR ; test uart flags for error JP DTRON ; turn DTR on JP DTROFF ; turn DTR OFF JP INIT ; initialise uart JP WAIT ; wait seconds JP MSWAIT ; wait milliseconds JP USERIN ; User-defined entry routine JP USEROUT ; User-defined exit routine JP GETVARS ; Get system variables JP SETPORT ; Set port (0 or 1) ; ; Spare jumps for compatibility with future versions ; JP SPARE ; Spares for later use JP SPARE ; Spares for later use JP SPARE ; Spares for later use JP SPARE ; spares for later use JP SPARE ; spares for later use JP SPARE ; spares for later use ; Main code starts here VERSN: DEFB '===> Ver. 1.5.1520.24.11.88.ZMPOVL <===' ; Screen print function SCRNPR: ; <== Insert your own code here CALL PRINT DB 'This function not supported.',CR,LF,0 ; <== End of your own code SPARE: RET ; User-defined entry routine: leave empty if not needed USERIN: RET ; User-defined exit routine: leave empty if not needed USEROUT:RET ; Get a character from the modem: return in HL ; (It is not necessary to test for status) MCHIN: ; <== Insert your own code here IN A,(DPORT) ; to get the character in A ; <== End of your own code LD L,A ; put in HL LD H,0 OR A ; set/clear Z RET ;Send a character to the modem MCHOUT: LD HL,2 ; get the character ADD HL,SP LD A,(HL) ; in A ; <== Insert your own code here OUT (DPORT),A ; <== End of your own code RET ; done ;Test for output ready: return TRUE (1) in HL if ok MORDY: ; <== Insert your own code here LD HL,0 ; Assume that the Transmit Buffer is full IN A,(LSPORT) ; Get Line Status AND TBMT ; Is the Transmit Buffer Empty? JR Z,TB.BUSY ; No, skip LD L,1 ; Yes, HL = 1 (TRUE) TB.BUSY: ; <== End of your own code LD A,L ; Set/clear Z OR A RET ;Test for character at modem: return TRUE (1) in HL if so MIRDY: ; <== Insert your own code here LD HL,0 ; Assume that no data is available IN A,(LSPORT) ; Get Line Status AND DAV ; Is Data Available? JR Z,NO.DAV ; No, skip LD L,1 ; Yes, HL = 1 (TRUE) NO.DAV: ; <== End of your own code LD A,L ; set/clear Z OR A RET ;Send a break to the modem: leave empty if your system can't do it SNDBRK: ; <== Insert your own code here ; This routine sends a 300 ms Break Tone and sets DTR low for the ; same length of time to disconnect the modem at both ends XOR A ; Clear reg A to OUT (MCPORT),A ; Set DTR and RTS low LD A,BRKS ; Set Break Tone OUT (LCPORT),A ; to go to 'break' level LD HL,300 ; wait 300 ms CALL WAITHLMS DSP EQU $+1 ; Inline code modification (data, stop, parity) LD A,WLS0+WLS1 ; Set 8 data bits, 1 stop bit, no parity OUT (LCPORT),A LD A,DTR ; Set DTR for proper Modem output level OUT (MCPORT),A ; to restore ; <== End of your own code RET ;Test UART flags for error: return TRUE (1) in HL if error MDMERR: ; <== Insert your own code here LD HL,0 ; Set HL = FALSE (0) ; <== End of your own code LD A,L ; set/clear Z OR A RET ;Turn DTR (and optionally RTS) ON. DTRON: ; <== Insert your own code here LD A,DTR ; Set DTR OUT (MCPORT),A ; <== End of your own code RET ;Turn DTR ( and RTS?) OFF DTROFF: ; <== Insert your own code here XOR A ; Clear reg A to OUT (MCPORT),A ; Set DTR and RTS low ; <== End of your own code RET ;Initialise the UART INIT: LD HL,2 ; get parameters ADD HL,SP EX DE,HL CALL GETPARM ; in HL LD (BRATE),HL ; baud rate CALL GETPARM LD (PARITY),HL ; parity CALL GETPARM LD (DATA),HL ; data bits CALL GETPARM LD (STOP),HL ; stop bits ; <== Insert your own code here DI ; Disable CPU Interrupts LD A,(BRATE) ; A = Baud rate number (see table below) CP 11+1 ; Allow speeds to 57,600 bps JR NC,BADRATE ; Skip if invalid baud rate LD (MSPEED),A ; else save for current BRATE LD E,A LD D,0 ; DE = Baud rate number LD HL,BAUD.RATES ; HL -> Start of baudrate divisor table ADD HL,DE ; Add it twice, each ADD HL,DE ; Divisor value occupies two bytes LD A,(HL) ; HL -> Desired divisor value, load HL INC HL ; indirect through HL [(HLIHL)] LD H,(HL) LD L,A ; HL = Divisor value LD A,D ; A = 0 OUT (IENREG),A ; Disable 8250 interrupts LD A,DLAB ; Set DLAB so we can use the baud rates OUT (LCPORT),A ; divisors LD A,L ; A = LSP of divisor OUT (LSPDIV),A ; Write divisor's "LSP" LD A,H ; A = MSP of divisor OUT (MSPDIV),A ; Write divisor's "MSP" LD A,(DATA) ; Get data bits count (7 or 8) CP 7 ; Is it 7 data bits? LD A,10B ; Assume it is JR Z,IS7BITS ; Yes, skip LD A,11B ; No, is 8 data bits, A = 11B IS7BITS: LD D,A ; Save data bits LD A,(STOP) ; Get number of desired stop bits (1 or 2) CP 1 ; Want one stop bit? LD A,0 ; Assume so JR Z,ONE.STOP ; Yes, skip LD A,100B ; No, set bit 2 - 2 stop bits wanted ONE.STOP: OR D ; OR in data bits info LD D,A ; and save data bits and stop bit info LD A,(PARITY) ; Get desired parity indicator (N, E or O) LD E,A ; and save it for possible later use CP 'N' ; Want no parity? LD A,D ; Assume so, A = data, stop, and parity (D,S,P) JR Z,HAVE.BITS ; Yes, skip LD A,E ; Get back desired parity indicator CP 'E' ; Want Even parity? LD A,PEN+PES ; Assume so, set even parity OR D ; and OR in data bits and stop bit info JR Z,HAVE.BITS ; Yes, skip LD A,PEN ; No, has to be Odd parity, set it OR D ; and OR in data bits and stop bit info HAVE.BITS: LD (DSP),A ; Set it for resetting after disconnect OUT (LCPORT),A ; Set desired word, stop and parity LD A,DTR ; Set DTR for proper MODEM operation OUT (MCPORT),A BADRATE: ; Skips above to here if baud rate bad EI ; Restore CPU interrupts ; using values below ; <== End of your own code RET STOP: DEFW 1 ; Stop bits (will be 1 or 2) PARITY: DEFW 'N' ; Parity (will be 'N', 'E' or 'O') DATA: DEFW 8 ; Data bits (will be 7 or 8) BRATE: DEFW 6 ; Baud rate: ;----------------------------------------------------------------------- ; Values of BRATE for each baud rate ; baud rate BRATE ; 110 0 ; 300 1 ; 450 2 ; 600 3 ; 710 4 ; 1200 5 ; 2400 6 ; 4800 7 ; 9600 8 ; 19200 9 ; 38400 10 ; 57600 11 ;----------------------------------------------------------------------- ; Baud rate divisor table BAUD.RATES: DEFW BD110 ; 0 - 110 baud DEFW BD300 ; 1 - 300 DEFW BD450 ; 2 - 450 DEFW BD600 ; 3 - 600 DEFW BD710 ; 4 - 710 DEFW BD1200 ; 5 - 1,200 DEFW BD2400 ; 6 - 2,400 DEFW BD4800 ; 7 - 4,800 DEFW BD9600 ; 8 - 9,600 DEFW BD19200 ; 9 - 19,200 DEFW BD38400 ; 10 - 38,400 DEFW BD57600 ; 11 - 57,600 ; ; Set the port. ZMP supplies either 0 or 1 as a parameter. ; setport: ld hl,2 ; get port number add hl,sp ex de,hl call getparm ; in HL (values are 0 and 1) ; <== Insert your own code here ; <== End of your own code ret ;**************************************************************************** ;Video terminal sequences: these are for ADM-3A: Modify as you wish ;Cursor addressing: (modified for H19/89) CURSADD: LD HL,2 ; get parameters ADD HL,SP EX DE,HL CALL GETPARM ; in HL LD (ROW),HL ; row CALL GETPARM LD (COL),HL ; column ; <== Insert your own code here ; using values in row and col CALL PRINT DEFB ESC,'Y',0 ; H19/89 leadin LD A,(ROW) ; row first ADD A,' ' ; add offset CALL COUT LD A,(COL) ; sane for column ADD A,' ' CALL COUT ; <== end of your own code RET ROW: DEFS 2 ; row COL: DEFS 2 ; column ;Clear screen: CLS: CALL PRINT DEFB ESC,'E',0 RET ;Inverse video on: INVON: CALL PRINT DEFB ESC,'p',0 RET ;Inverse video off: INVOFF: CALL PRINT DEFB ESC,'q',0 RET ;Turn off cursor: HIDE: CALL PRINT DEFB ESC,'x5',0 RET ;Turn on cursor: SHOW: CALL PRINT DEFB ESC,'y5',0 RET ;Save cursor position: SAVECU: CALL PRINT DEFB ESC,'j',0 RET ;Restore cursor position: RESCU: CALL PRINT DEFB ESC,'k',0 RET ;**************************************************************************** ;Service modem interrupt: MINT: RET ; my system doesn't need this ;Initialise interrupt vectors: INVEC: RET ; ditto ;De-initialise interrupt vectors: DINVEC: RET ; ditto ;****************** End of user-defined code ******************************** ; Don't change anything below this point. We needed some assembly language ; stuff for speed, and this seemed like a good place to put it. ;Modem character test for 100 ms MRD: PUSH BC ; save bc LD BC,100 ; set limit MRD1: CALL MIRDY ; char at modem? JR NZ,MRD2 ; yes, exit LD HL,1 ; else wait 1ms CALL WAITHLMS DEC BC ; loop till done LD A,B OR C JR NZ,MRD1 LD HL,0 ; none there, result=0 XOR A MRD2: POP BC RET ; Inline print routine: destroys A PRINT: EX (SP),HL ; get address of string PLOOP: LD A,(HL) ; get next INC HL ; bump pointer OR A ; done if zero JR Z,PDONE CALL COUT ; else print JR PLOOP ; and loop PDONE: EX (SP),HL ; restore return address RET ; and quit ; ;Output a character in A to the console ; COUT: PUSH BC ; save regs PUSH DE PUSH HL LD E,A ; character to E LD C,2 CALL BDOS ; print it POP HL POP DE POP BC RET ;Wait(seconds) WAIT: LD HL,2 ADD HL,SP EX DE,HL ; get delay size CALL GETPARM ; fall thru to.. ;Wait seconds in HL WAITHLS: PUSH BC ; Save BC PUSH DE ; DE PUSH IX ; And IX LD IX,0 ; Then point IX to 0 ; So we don't upset memory-mapped I/O ; ; Calculate values for loop constants. Need to have two loops to avoid ; 16-bit overflow with clock speeds above 9 MHz. ; OUTERVAL EQU (CLKSPD/10)+1 INNERVAL EQU (6667/OUTERVAL)*CLKSPD ; WAIT10: LD B,OUTERVAL ; WAIT11: LD DE,INNERVAL ; WAIT12: BIT 0,(IX) ; Time-wasters BIT 0,(IX) BIT 0,(IX) ; 20 T-states each BIT 0,(IX) BIT 0,(IX) BIT 0,(IX) DEC DE LD A,E LD A,D OR E JR NZ,WAIT12 ; 150 T-states per inner loop DJNZ WAIT11 ; Decrement outer loop DEC HL ; Ok, decrement count in hl LD A,H OR L JR NZ,WAIT10 POP IX ; Done -- restore ix POP DE ; De POP BC ; And bc RET ;Wait milliseconds MSWAIT: LD HL,2 ADD HL,SP EX DE,HL ; get delay size CALL GETPARM ; fall thru to.. ;Wait milliseconds in HL WAITHLMS: PUSH DE W1MS0: LD DE,39 * CLKSPD W1MS1: DEC DE LD A,D OR E JR NZ,W1MS1 DEC HL LD A,H OR L JR NZ,W1MS0 POP DE RET ;Get next parameter from (de) into hl GETPARM: EX DE,HL ; get address into hl LD E,(HL) ; get lo INC HL LD D,(HL) ; then hi INC HL ; bump for next EX DE,HL ; result in hl, address still in de RET ; Get address of user-defined variables GETVARS: LD HL,USERVARS RET USERVARS: DEFW OVERDRIVE ; OVR etc. drive/user DEFW OVERUSER IF ($ - JUMPTAB) GT OVSIZE TOOBIG: JP ERRVAL ; Overlay too large! ENDIF END