; ; Overlay to ZMP (Z-Modem Program), for the Kaypro CP/M computers. ; (Z80 SIO and 8116 baudrate generator.) ; ; Name: ZMO-KP05.MAC ; ; Dated: November 25, 1988 ; ; Written by - ; Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia. ; ; 89/04/12 - Modified to ZMP v1.5 - George Conover ; KP05 - Nov. 24, 88. Updated for ZMP version 1.4 (overlay drive/user ; equates). Added conditional to check RTS/CTS signals. ; Bill Duerr, GEnie ID: B.DUERR ; DKUG RBBS [313] 772-0522 ; ; KP04 - Oct. 22, 88. Updated to allow program to be reentered properly, ; for 8-N-1 only -- still problems with even/odd parity. ; Bill Duerr, GEnie ID: B.DUERR ; DKUG RBBS [313] 772-0522 ; ; KP03 - Oct. 12, 88 Modified to ZMP v1.3 standard rjm ; ; ; Insert your own code as necessary in this 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 ; db '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 15/8/88 ; ; false equ 0 true equ not false ; ; If the following equate is set to true, code will be added to set ; the RTS modem signal, telling the modem not to send any characters ; till RTS is reset, and also to check CTS if characters may be sent. ; This allows the Kaypro screen to keep up with the characters sent ; over the modem lines at higher speeds. (The modem must be able to ; recognize RTS and set CTS for this to work.) ; rtscts equ true ; ;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 'A' ; Drive to find overlay files on ('A'-'P') overuser equ 15 ; User area to find files ;------------------------------------------------------------------------------ ;User-set variables: clkspd equ 4 ; Processor clock speed in MHz mspeed equ 003ch ; Current baud rate: as used by BYE etc ; This MUST be the same as Mspeed in ; ZMP.H dport equ 04h ; Kaypro SIO data port sport equ dport+2 ; Modem control port mdrcv equ 01h ; Modem receive ready mdsnd equ 04h ; Modem send ready bit mdtxe equ 01h ; Modem send buffer empty, holding buffer empty rsterr equ 30h ; Reset parity and overrun flags - register 0 reg1ins equ 0 ; No interrupts - register 1 reg3ins equ 0c1h ; 8 Rx bits, Rx enable reg4ins equ 44h ; 16X baud rate, 1 stop bit, no parity reg5ins equ 0eah ; 8 Tx bits, Tx enable, RTS, DTR bauda equ 00h ; 8116 port for baudrate rstsio equ 18h ; Reset the SIO dcd equ 08h ; Data Carrier Detect dtr equ 80h ; Data Terminal Ready rts equ 02h ; Request to send cts equ 20h ; Clear to send brk equ 10h ; SIO Break sioerr equ 70h ; SIO error userdef equ 00145h ; origin of this overlay: get this value ; from the .SYM file produced when ZMP.COM ; is linked ovsize equ 0400h ; max size of this overlay org userdef esc equ 1bh ctrlq equ 11h cr equ 0dh lf equ 0ah bdos equ 5 ;Jump table for the overlay: do NOT change this jump_tab: 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 ; spare for later use jp spare ; spare for later use jp spare ; spare for later use jp spare ; spare for later use jp spare ; spare for later use jp spare ; spare for later use ; ; Main code starts here ; codebgn equ $ ; ;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 userin: ret ; User-defined exit routine userout: ; Leave RTS off if rtscts ld a,05h ; Select register 5 out (sport),a ; Send to the status port ld a,(reg5) ; Get register 5 settings and 255-rts ; Turn off RTS out (sport),a ; Send to the status port endif ; rtscts ret ;Get a character from the modem: return in HL ; It is not necessary to test for status mchin: ;-- Code added specific to Kaypro in a,(dport) ; get the character in A ; ; This routine checks parity, and if parity is not "none", strips high bit. ; This is needed, even if the filter is turned on, because CONNECT message ; is not filtered. ; ld l,a ; Save in L ld a,(parity) ; Check parity cp 'N' ; No parity? ld a,l ; Get the character back jr z,mchin1 ; Bypass following kludge and 7fh ld l,a ; put in HL mchin1: if rtscts ld a,05h ; Select register 5 out (sport),a ; Send to the status port ld a,(reg5) ; Get register 5 settings and 255-rts ; Turn off RTS out (sport),a ; Send to the status port endif ; rtscts ;-- End of this block of machine specific code ld a,l ; get character from 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 ;-- Code added specific to Kaypro out (dport),a ; Put the character to the serial port ;-- End of this block of machine specific code ret ; done ;Test for output ready: return TRUE (1) in HL if ok mordy: ;-- Code added specific to Kaypro ld hl,0 ; Assume not ready ; if rtscts ld a,10h ; Reset register 0 out (sport),a ; Send to the status port in a,(sport) ; read status port and cts ; Is clear to send up jr z,mordy1 ; Branch if not clear to send endif ; rtscts ; ld a,10h ; Reset register 0 out (sport),a ; Send to the status port in a,(sport) ; Read status port and mdsnd ; Isolate transmit empty bit jr z,mordy1 ; Branch if not ready inc hl ; otherwise set HL to indicate ready mordy1: ;-- End of this block of machine specific code ld a,l or a ; set/clear Z ret ;Test for character at modem: return TRUE (1) in HL if so mirdy: ;-- Code added specific to Kaypro ld a,05h ; Select register 5 out (sport),a ; Send to the status port ld a,(reg5) ; Get register 5 settings or rts ; Turn on RTS out (sport),a ; Send to the status port ld hl,0 ; Assume not ready ld a,10h ; Reset register 0 out (sport),a ; Send to the status port in a,(sport) ; Get the status and mdrcv ; Isolate receive ready bit jr z,mirdy1 ; Branch if not ready inc hl ; otherwise set HL to indicate ready mirdy1: ;-- End of this block of machine specific code ld a,l or a ; set/clear Z ret ;Send a break to the modem: leave empty if your system can't do it sndbrk: ;-- Code added specific to Kaypro ld a,5 ; Select register 5 out (sport),a ; Send to the status port ld a,(reg5) ; Get parameters for register 5 or brk ; Set the break tone out (sport),a ; Send to the status port ;-- End of this block of machine specific code ld hl,300 call waitms ; wait 300 mS ;-- Code added specific to Kaypro ld a,5 ; Select register 5 out (sport),a ; Send to the status port ld a,(reg5) ; Restore register 5 settings out (sport),a ; Send to the status port ;-- End of this block of machine specific code ret ;Test UART flags for error: return TRUE (1) in HL if error mdmerr: ;-- Code added specific to Kaypro ld hl,0 ; Assume no error ld a,011h ; Select read register 1 out (sport),a ; Send to the status port in a,(sport) ; Get error status and sioerr ; Mask all but error bits ret z ; Return zeor in HL if no error inc hl ; Otherwise set HL to indicate error ret ; Return ;Turn DTR (and optionally RTS) ON. dtron: ;-- Code added specific to Kaypro ld a,05h ; Select register 5 out (sport),a ; Send to the status port ld a,(reg5) ; Get register 5 settings out (sport),a ; Send to the status port ;-- End of this block of machine specific code ret ;Turn DTR ( and RTS?) OFF dtroff: ;-- Code added specific to Kaypro ld a,05h ; Select register 5 out (sport),a ; Send to the status port ld a,(reg5) ; Get register 5 settings and 255-dtr ; Turn off DTR out (sport),a ; Send to the status port ;-- End of this block of machine specific code ret ;Initialise the UART init: ld hl,2 ; get parameters add hl,sp ld a,(hl) ; get lo ld (mspeed),a ; save in baud rate low memory inc hl inc hl ; bump for next ld a,(hl) ; get lo and 5Fh ; Convert to upper case ld (parity),a ; parity inc hl inc hl ; bump for next ld a,(hl) ; get lo and 0fh ; Make sure binary ld (data),a ; Save data bits cp 7 ; but 7 if required ld a,reg5ins ; 8 Tx bits, Tx enable, RTS, DTR jr nz,setbs ld a,reg5ins-040h ; Turn bit off setbs: ld (reg5),a inc hl inc hl ; bump for next ld a,(hl) ; get lo and 0fh ; Make sure binary ld (stop),a ; stop bits ; <== Insert your own code here ;-- Code added specific to Kaypro ld a,10h ; Reset register 0 out (sport),a ; Send to the status port in a,(sport) ; read status port and DCD ; Is carrier up jr nz,initr ; Branch if carrier already there ld A,0 ; Select register 0 out (sport),a ; Send to status port ld a,rstsio ; Reset SIO - 18h out (sport),a ; Send to status port ; ld A,4 ; Select register 4 out (sport),a ; Send to status port ld a,(parity) ; do parity ld e,003h ; assume even parity cp 'E' ; even? jr z,setstop ; yes ld e,001h ; try odd cp 'O' jr z,setstop ld e,0 ; Indicate no parity setstop: ld a,(stop) ; set stop bits cp 2 ld a,reg4ins ; 16X baud rate, 1 stop bit, no parity jr nz,onestop or 00ch ; set bits 2 and 3 onestop: or e ; put parity bits in the register ; out (sport),a ; Send to status port ; ld a,3 ; Select register 3 out (sport),a ; Send to status port ; ld a,(data) ; get data bits parameter field cp 7 ; is 7 required ld a,reg3ins ; 8 Rx bits, Rx enable jr nz,setbr and 07fh setbr: out (sport),a ; Set Rx bits ld a,5 ; Select register 5 out (sport),a ; Send to status port ld a,(reg5) ; Get register 5 settings out (sport),a ; Set tx bits ; ld a,1 ; Select register 1 out (sport),a ld a,reg1ins ; No interrupts out (sport),a ; Send to status port ; ld a,(mspeed) ; set baud rate: get index ld hl,brval ld e,a ; rate to DE ld d,0 add hl,de ld a,(hl) ; get baud rate value out (bauda),a ; <== End of your own code initr: ret ; ; Baud rate factors, output to bauda to select baud rate ; bd10 equ 02h ; 110 baud rate 0 bd30 equ 05h ; 300 baud rate 1 bd12 equ 07h ; 1200 baud rate 5 bd24 equ 0ah ; 2400 baud rate 6 bd48 equ 0ch ; 4800 baud rate 7 bd96 equ 0eh ; 9600 baud rate 8 bd19k equ 0fh ; 19.2k baud rate 9 ;Values for control reg for each baud rate: 0 if invalid brval: ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 db 00,01,00,00,00,07,10,12,14,15 ; <== End of your own code ret brate: db 6,0 ; baud rate: ; 0 = 110 baud 1 = 300 baud 2 = 450 baud ; 3 = 600 baud 4 = 710 baud 5 = 1200 baud ; 6 = 2400 baud 7 = 4800 baud 8 = 9600 baud ; 9 = 19200 baud parity: db 'N',0 ; parity (will be 'N', 'E' or 'O') data: db 8,0 ; data bits (will be 7 or 8) stop: db 1,0 ; stop bits (will be 1 or 2) reg5: db reg5ins ; ; 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: 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 db esc,'=',0 ; ADM-3A 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: ds 2 ; row col: ds 2 ; column ;Clear screen: cls: call print db 01ah,0 ret ;Inverse video on: invon: call print db esc,'B','0',esc,'B','1',0 ret ;Inverse video off: invoff: call print db esc,'C','0',esc,'C','1',0 ret ;Turn off cursor: hide: call print db esc,'C','4',0 ret ;Turn on cursor: show: call print db esc,'B','4',0 ret ;Save cursor position: savecu: call print defb esc,'B','6',0 ret ;Restore cursor position: rescu: call print defb esc,'C','6',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 ; character at modem? jr nz,mrd2 ; yes, exit ld hl,1 ; else wait 1ms call waitms 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 and HL 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 ; Save the character to E for BDOS routine ld c,2 ; BDOS conout routine 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 waits: 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 waitms: 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: dw overdrive ; .OVR etc. drive/user dw overuser if ($ - codebgn) gt ovsize toobig: jp errval ; Overlay too large! endif end