home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ENTERPRS
/
CPM
/
TERMS
/
ZMP15.PMA
/
ZMOMYZ80.Z80
< prev
next >
Wrap
Text File
|
1979-12-31
|
13KB
|
650 lines
;-----------------------------------------------------------------------------
;
; Overlay for ZMP (Z-Modem Program)
;
; Name ZMOMYZ80.Z80
;
; Dated Feb 27, 1992
;
; VERSION 0.2 - Testing, but seems to work.
;
; Written by -
; Simeon Cran, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia.
;
;-----------------------------------------------------------------------------
;
; Notes on modifying this file (from Ron Murray):
;
; 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 the 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.
;
; An inline print routine is provided for printing strings
; in the usual way: usage is
;
; call print
; db 'required string',0
;
;---------------------------------------------------------------------------
false equ 0
true equ not false
EXTBIOS equ 0fffdh
;------------------------------------------------------------------------------
; User-set variables:
clkspd equ 10 ; 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 13 ; 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
;;; .hd64 ; use 64180 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
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
jp setport ; set port (1 or 2)
; 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
ld a,(portbase+0)
ld c,a
in a,(c) ; Get the character
ld l,a ; put it 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
push bc
ld a,(portbase+0)
ld c,a
ld a,(hl)
out (c),a
pop bc
ret ; done
;Test for output ready: return TRUE (1) in HL if ok
mordy:
push bc
ld a,(portbase+5)
ld c,a
ld hl,1 ; Assume ready
tstio 20h
jr nz,mordyyes ; Jump if ready
dec hl
mordyyes:
ld a,l ; set/clear Z
or a
pop bc
ret
;Test for character at modem: return TRUE (1) in HL if so
mirdy:
push bc
ld hl,0 ; Assume no character
ld a,(portbase+5)
ld c,a
tstio 01h
jr z,mirdyno ; Jump if not ready
inc hl
mirdyno:
ld a,l ; set/clear Z
or a
pop bc
ret
;Send a break to the modem.
sndbrk:
ld a,(portbase+3)
ld c,a
in a,(c)
or 40h ; Set bit to turn break on
out (c),a
push bc
ld hl,300 ; wait 300 mS
call waithlms
pop bc
in a,(c)
and 10111111b
out (c),a
ret
;
;Test UART flags for error: return TRUE (1) in HL if error.
mdmerr: push bc
ld hl,0 ; Assume no error
ld a,(portbase+5)
ld c,a
tstio 00011110b
jr z,mdmerrNO
inc hl
mdmerrNO:
ld a,l ; set/clear Z
or a
pop bc
ret
;Turn DTR ON
dtron: ld a,(portbase+4)
ld c,a
in a,(c)
bit 0,a
ret nz ; Return if already on
or 1 ; Turn DTR on
out (c),a
ret
;Turn DTR OFF
dtroff:
ld a,(portbase+4)
ld c,a
in a,(c)
bit 0,a
ret z ; Return if already off
and 11111110b
out (c),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)
ld (initflg),hl ; Set the initflag
initagain:
push bc
push de
ld a,(portbase+1)
ld c,a
xor a
out (c),a ; Prevent interrupts
ld b,10011111b ; Line control register value set for:
; DLAB access
; Break off
; Parity unstuck
; Even...
; Parity on
; 2 stop bits
; 8 data bits
ld a,(data) ; Get number of data bits (7,8)
cp 7
jr z,data7
set 0,b ; Make it 8 bits
data7:
ld a,(stop) ; Get number of stop bits
dec a
jr nz,stop2
res 2,b
stop2:
ld a,(parity)
cp 'E'
jr z,parityE
cp 'O'
jr z,parityO
; Make it no parity
res 3,b
jr parityE
parityO:
res 4,b
parityE:
ld a,(portbase+3)
ld c,a
ld a,b
out (c),a ; Output it ready to set baudrate
ld hl,(brate)
ld c,l
add hl,hl ; Double for word offset
ld de,baudtbl
add hl,de ; Point to correct entry
ld e,(hl)
inc hl
ld d,(hl)
ld a,d
or e
jr z,nobaud
ld a,c
ld (mspeed),a
ld a,(portbase+0)
ld c,a
out (c),e ; Do low byte
inc c
out (c),d ; Do high byte
nobaud:
ld a,(portbase+3)
ld c,a
ld a,b ; Restore DLAB
res 7,a
out (c),a
ld a,(portbase+4)
ld c,a
in a,(c)
or 2 ; Make sure DSR is on
out (c),a
call dtron ; Turn on DTR as well
pop de
pop bc
ret
;--------------------------------------------------------------------------
stop: dw 1 ; stop bits
parity: dw 'N' ; parity
data: dw 8 ; data bits
brate: dw 7 ; baud rate
baudtbl:dw 417h ;110
dw 180h ;300
dw 100h ;450
dw 0c0h ;600
dw 0a2h ;710
dw 060h ;1200
dw 030h ;2400
dw 018h ;4800
dw 0ch ;9600
dw 06h ;19200
dw 03 ;38400
dw 0
dw 0
portbase: ; This table is to help access the correct port address
db 0,1,2,3,4,5,6,7
initflg:
dw 0 ; Set when init is called.
;--------------------------------------------------------------------------
;Values of brate for each baud rate
;
; baud rate brate divisor
;
; 110 0 417h
; 300 1 180h
; 450 2
; 600 3 0c0h
; 710 4
; 1200 5 060h
; 2400 6 030h
; 4800 7 018h
; 9600 8 0ch
; 19200 9 06h
; 38400 10 03h
; 57600 11 -
; 76800 12 -
;
; Set the port. ZMP supplies either 0 or 1 as a parameter. You're on your
; own here -- your system is bound to be different from any other! You may
; implement a software switch on all the modem-dependent routines, or perhaps
; you can have one or two centralised routines for accessing the UARTs and
; modify the code from this routine to select one or the other. (Who said
; there was anything wrong with self-modifying code?). If you have only one
; UART port, or if you don't want to go through all the hassles, just have
; this routine returning with no changes made. Note that ZMP calls this
; routine with both values for the port on initialisation.
;
setport:
ld hl,2 ; get port number
add hl,sp
ex de,hl
call getparm ; in HL (values are 0 and 1)
ld a,l ; Get the port number
ld (port),a ; Save current port number for later
ld hl,portbase1 ; Assume port 1
or a
jr z,setport1 ; Jump if port 1
ld hl,portbase2
setport1:
ld bc,8
ld de,portbase
ldir ; Copy the new port values
ld a,(initflg)
or a
ret z ; If no port initialised, then don't do it.
jp initagain ; And make sure the port is initialised.
port: dw 0
portbase1: db 0,1,2,3,4,5,6,7
portbase2: db 8,9,10,11,12,13,14,15
;****************************************************************************
;Video terminal sequences:
;Cursor addressing:
cursadd:
ld hl,2 ; get parameters
add hl,sp ; Point to parameters
ld e,(hl) ; Get row
inc hl
inc hl
ld d,(hl) ; Get column
ld hl,2020h ; Offsets
add hl,de
ld (row),hl ; Set row and column
call print
db esc,'=' ; ADM 3A leadin
row: db 0
col: db 0
db 0 ; Terminating 0
ret
;Clear screen:
cls: ld a,1ah
jp cout
;Inverse video on:
invon: call print
db esc,'G4',0
ret
;Inverse video off:
invoff: call print
db esc,'G0',0
ret
;Turn off cursor:
hide: call print
db esc,'.1',0
ret
;Turn on cursor:
show: call print
db esc,'.3',0
ret
;Save cursor position:
savecu: ret
;Restore cursor position:
rescu: ret
;****************************************************************************
;Service modem interrupt:
mint: ret
;Initialise interrupt vectors:
invec: ret
;De-initialise interrupt vectors:
dinvec: ret
;****************** End of user-defined code ********************************
; Do not change anything below here.
; For best results this code has been changed. Instead of calling mirdy
; then waiting 100 times, it calls mirdy many more times and does no
; waiting. The number of times to call mirdy needs to be changed according
; to the speed of the system, but it doesn't matter too much if it calls too
; many times.
;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
push bc
ld bc,4000 ;|||||
mrd1: call mirdy
jr nz,mrd2
dec bc
ld a,b
or c
jr nz,mrd1
ld hl,0
xor a
mrd2: pop bc
ld a,l
or a
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
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
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