;----------------------------------------------------------------------------- ; ; Heath-89 Overlay for ZMP (Z-Modem Program) ; modifications by Howard Dutton ; ; Name ZMO-H89.Z80 ; ; Dated Sep 14, 1988 ; ; Written by - ; Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia. ; ; Modified to ZMP v1.2 standard rjm 15/9/88 ; Modified to ZMP v1.3 standard rjm 11/10/88 ; Modified to ZMP v1.4 standard rjm 20/11/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. Assemble as follows: ; ; SLR ZMO-xx01/h ; MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX ; or ; M80 =ZMO-xx01.Z80 ; RELHEX ZMO-xx01 ; MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX ; ; ; (Don't use L80 without changing the source for assembly as a ; cseg file.) ; ;----------------------------------------------------------------------------- ; ; ; 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 contact me for another version. 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 ;------------------------------------------------------------------------------ ; User-set variables: clkspd equ 6 ; Processor clock speed in MHz debug equ false ; 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 'A' ; 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 03ch ; location of current baud rate. ovsize equ 0400h ; max 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 mport equ 0d8h ; the modem port on a h88-3 serial card conport equ 0e0h ; the console serial port on a H89 esc equ 1bh ctrlq equ 11h cr equ 0dh lf equ 0ah bdos equ 5 codebgn equ $ ;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 ; 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 ; ;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 mchin: push bc in a,(mport) ld l,a ; put in HL ld h,0 or a ; set/clear Z pop bc ret ;Send a character to the modem mchout: ld hl,2 ; get the character add hl,sp ld a,(hl) out (mport),a ret ; done ;Test for output ready: return TRUE (1) in HL if ok mordy: ld hl,0 ; in a,(mport+5) ; bit 5,a ; bit 5 is set if uart is ready for a char jp z,mordy1 ; ld hl,1 mordy1: ld a,l ; set/clear Z or a ret ;Test for character at modem: return TRUE (1) in HL if so mirdy: ld hl,0 ; in a,(mport+5) ; bit 0,a ; bit 0 is set if data is ready jp z,mirdy1 ; ld hl,1 mirdy1: 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: in a,(mport+3) ; set 6,a ; set break bit out (mport+3),a ; push af ld hl,300 ; wait 300 mS call waithlms pop af res 6,a ; reset break bit out (mport+3),a ; ret ; ;Test UART flags for error: return TRUE (1) in HL if error. mdmerr: ld hl,0 in a,(mport+5) ; get line status and 00001110B ; mask jp z,mdmer1 ; a should = 0 if everything is ok ld hl,1 ; mdmer1: ld a,l ; set/clear Z or a ret ;Turn DTR ON dtron: in a,(mport+4) ; set 0,a ; set the DTR bit out (mport+4),a ; ret ;Turn DTR OFF dtroff: in a,(mport+4) ; res 0,a ; reset the DTR bit out (mport+4),a ; 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 (BINARY 7 or 8) call getparm ld (stop),hl ; stop bits (BINARY 1 or 2) ; get the 8250 ready for programming ld a,0 ; clear interrupts out (mport+1),a ; ld a,00010000B ; set to loop-back mode out (mport+4),a ; ; program the baud-rate (if it's valid) ld hl,(brate) ; check to see if baud-rate is valid ld de,12 ; or a ; clear carry sbc hl,de ; hl=brate-12 jp p,prb1 ; negitive if brate is 0..11 ld a,l ; ld (mspeed),a ; let zmp know it's valid ld a,10000000B ; set divisor latch access bit out (mport+3),a ; ld hl,(brate) ; compute offset to baud-rate divisor add hl,hl ; ex de,hl ; ld hl,brtbl ; add hl,de ; HL now has address of divisor ld a,(hl) ; get the low-order byte out (mport),a ; inc hl ; ld a,(hl) ; out (mport+1),a ; ; program the: type of parity / # data bits / # stop bits prb1: ld b,0 ; set the LCR value (in B for now) to 0 ld a,(parity) ; set bits in B to type of parity cp 'N' ; jp z,parN ; cp 'E' ; jp z,ParE ; cp 'O' ; jp z,ParO ; Skip3: ld a,(Data) ; set bits in B to # of data bits cp 7 ; jp z,data7 ; cp 8 ; jp z,data8 ; Skip4: ld a,(Stop) ; cp 1 ; jp z,Stop1 ; cp 2 ; jp z,Stop2 ; Skip5: ld a,b ; get 'LCR' value out (mport+3),a ; (also de-selects divisor access) ; take 8250 out of loop-back mode in a,(mport) ; read a char add hl,hl ; waste some time add hl,hl ; in a,(mport) ; read another char ld a,0 ; out (mport+4),a ; take 8250 out of loop-back mode ret ; Types of parity ParN: jp Skip3 ParE: set 3,b set 4,b jp Skip3 ParO: set 3,b jp Skip3 ; Number of data bits Data7: set 1,b jp Skip4 Data8: set 0,b set 1,b jp Skip4 ; Number of stop bits Stop1: jp Skip5 Stop2: set 2,b jp Skip5 ; baud rate divisor table for 8250 brtbl: dw 1047 ; 110 0 dw 384 ; 300 1 dw 256 ; 450 2 dw 192 ; 600 3 dw 162 ; 710 4 dw 96 ; 1200 5 dw 48 ; 2400 6 dw 24 ; 4800 7 dw 12 ; 9600 8 dw 6 ; 19200 9 dw 3 ; 38400 10 dw 2 ; 57600 11 ;-------------------------------------------------------------------------- stop: dw 1 ; stop bits parity: dw 'N' ; parity data: dw 8 ; data bits brate: dw 5 ; baud rate: 1200 ;-------------------------------------------------------------------------- ;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 ; ;**************************************************************************** ;Video terminal sequences: these are for the H19 ;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 ; using values in row and col call print db esc,'Y',0 ; H19 leadin ld a,(row) ; row first add a,' ' ; add offset call cout ld a,(col) ; sane for column add a,' ' call cout ret row: ds 2 ; row col: ds 2 ; column ;Clear screen: cls: call print db esc,'E',0 ret ;Inverse video on: invon: call print db esc,'p',0 ret ;Inverse video off: invoff: call print db esc,'q',0 ret ;Turn off cursor: hide: call print db esc,'x5',0 ret ;Turn on cursor: show: call print db esc,'y5',0 ret ;Save cursor position: savecu: call print db esc,'j',0 ret ;Restore cursor position: rescu: call print db 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 ******************************** ; Do not change anything below here. ;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 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 ; 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 waiths: 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: dw overdrive ; .OVR etc. drive/user dw overuser if ($ - codebgn) gt ovsize toobig: jp errval ; Overlay too large! endif end