You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

663 lines
13 KiB

;-----------------------------------------------------------------------------
;
; Overlay for ZMP (Z-Modem Program)
;
; Name ZMO-RW01.Z80
;
; ROMWBW version using HBIOS and https://github.com/mecparts/zmp version of zmodem
; Databits, stop bit, parity setting not supported.
; All modem/serial i/o is through the hbios.
; Timing delay calculations based on hbios reported cpu speed.
; Only 1 port is supported by the mecports version of zmp.
; Port setting supports 2 port, port A is CIO 1, port B is CIO 2
; This overlay is compatible with Ron Murray's original ZMP15 which support two ports.
; Teraterm users may need to change the ZmodemWinSize value to 1024 in teraterm.ini file.
;
;-----------------------------------------------------------------------------
;
false equ 0
true equ not false
;
;------------------------------------------------------------------------------
;
; User-set variables:
;
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 0 ; Drive to find overlay files on ('A'-'P')
overuser equ 0 ; User area to find files
;
; Initial baud rate code
;
initbr equ 10 ; Refer to "baudtbl" table below - brate column
;
;------------------------------------------------------------------------------
;
; 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
;
esc equ 1bh
ctrlq equ 11h
cr equ 0dh
lf equ 0ah
bdos equ 5
fcb equ 05ch+1 ; Command line
;
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 (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
;
; Port 0 & 1 defaults. Can be overwritten by command line
;
hbport0 db 1 ; default hbios CIO serial port 0
hbport1 db 2 ; alternate hbios CIO serial port 1
port: db 1 ; current cio port.
;
; Main code starts here
;
;Screen print function
scrnpr: call print
db 'This function not supported.',cr,lf,0
spare: ret
;
; User-defined entry routine:
;
; forcing reinit will resend AT command to modem, reset
; current line defaults and eat up buffered characters
;
; Get and set modem/serial ports to use from the command line
;
; Get the cpu speed reported by romwbw hbios and calculate
; the three required loop counter values for timing:
;
; outerva (outv)
; innerval (inv)
; millisv (msv)
;
userin: ld a,-1 ; force re-init
ld (mspeed),a
;
ld a,(fcb) ; first character
cp ' ' ; of parsed filename
jr z,dport1 ; is port 0
sub '0'
ld (hbport0),a ; set CIO for port 0
ld (port),a ; reconfigure default
dport0: ld a,(fcb+1) ; second character
cp ' ' ; of parsed filename
jr z,dport1 ; is port 1
sub '0'
ld (hbport1),a
dport1: push bc
ld bc,0f8f0h ; get clock speed in l
rst 08
;
; outerval equ (clkspd / 10) + 1
;
push hl ; save clock speed
ld h,0
ld c,10
call div_hl_c ; result in hl
ld a,l
inc a
ld (outv),a ; save outerval
;
; innerval equ (6667 / outerval) * clkspd
;
ld c,a
ld hl,6667
call div_hl_c ; result in hl
;
ex de,hl
pop hl ; recall clock
ld a,l ; save
push af ; clock speed
;
call mult_a_de
ld (inv),hl ; save innerval
;
; ld de,39 * clkspd
;
pop af ; recall clock speed
ld de,39
call mult_a_de
ld (msv),hl ; save msec value
;
pop bc
ret
;
outv: ds 1 ; outer value
inv: ds 2 ; inner value
msv: ds 2 ; millisec value
;
; maths helpers
;
mult_a_de: ; https://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Multiplication
ld c,0
ld h,c
ld l,h
add a,a ; optimised 1st iteration
jr nc,$+4
ld h,d
ld l,e
ld b,7
_loop2: add hl,hl
rla
jr nc,$+4
add hl,de
adc a,c
djnz _loop2 ; result in ahl
ret
;
div_hl_c: ; https://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division
xor a
ld b,16
_loop1: add hl,hl
rla
jr c,$+5
cp c
jr c,$+4
sub c
inc l
djnz _loop1 ; result in hl
ret
;
; User-defined exit routine: leave empty if not needed
userout:call show
ret
;
;Get a character from the modem: return in HL
mchin: push bc
ld b,00h
ld hl,port
ld c,(hl)
rst 08
ld l,e
pop bc
ret
;Send a character to the modem
mchout: ld hl,2 ; get the character
add hl,sp
ld e,(hl)
ld b,01h
ld hl,port
ld c,(hl)
rst 08
ret ; done
;Test for output ready: return TRUE (1) in HL if ok
mordy: ld b,03h
ld hl,port
ld c,(hl)
rst 08
ld h,0
or a
jr z,modrdy1
ld a,1
or a
modrdy1:ld l,a
ret
;Test for character at modem: return TRUE (1) in HL if so
mirdy: push bc
ld b,02h
ld hl,port
ld c,(hl)
rst 08
ld h,0
or a
jr z,mirdy1
ld a,1
or a
mirdy1: ld l,a
pop bc
ret
;
;Send a break to the modem: leave empty if your system can't do it
sndbrk: ld hl,300 ; wait 300 mS
call waithlms
ret
;
;Test UART flags for error: return TRUE (1) in HL if error.
mdmerr: xor a ; set/clear Z
ld h,a
ld l,a
ret
;
;Turn DTR ON
dtron:
; ret
;
;Turn DTR OFF
dtroff:
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 a,(port) ; get device type
ld c,a
ld b,06h
rst 08
or a ; check if valid
jr nz,initerr
;
ld a,(brate) ; get baud rate to set
ld c,a
ld b,0
ld hl,baudtbl
add hl,bc
ld a,(hl) ; convert to encoded hbios
cp a,-1
jr z,initerr
;
push af
ld a,(port) ; get line characteristics
ld c,a
ld b,05h
rst 08
ld a,d ; mask out exisitng
and 11100000b ; replace with rate
ld d,a
pop af
or d
ld d,a
;
ld b,04h ; set new
ld a,(port) ; speed
ld c,a
rst 08
or a
jr nz,initerr
;
call print
db 'Initializing device: ',0
call diport
;
ld a,(brate) ; load mspeed with the current brate value if
ld (mspeed),a ; the new rate is valid. See table of values below.
ret
;
initerr:call print
db lf,lf,'Initization failed, device: ',0
call diport
call show ; show cursor, then ...
jp 0 ; bail out to avoid system hang!
;
diport: ld a,(port) ; Display port
diport1:add a,'0'
call cout
call print
db cr,lf,0
ret
;
;--------------------------------------------------------------------------
stop: dw 1 ; stop bits
parity: dw 'N' ; parity
data: dw 8 ; data bits
brate: dw initbr ; baud rate:
;--------------------------------------------------------------------------
;
;Values of brate for each baud rate
;
; hb encode baud rate brate
;
baudtbl:
db -1 ; 110 0 not supported
db 2 ; 300 1
db 17 ; 450 2
db 3 ; 600 3
db -1 ; 710 4 not supported
db 4 ; 1200 5
db 5 ; 2400 6
db 6 ; 4800 7
db 7 ; 9600 8
db 8 ; 19200 9
db 9 ; 38400 10
db 24 ; 57600 11
db 10 ; 76800 12
;
; Set the port. ZMP supplies either 0 or 1 as a parameter.
; Note that ZMP calls this routine with both values
; for the port on initialisation.
;
; Only originl ZMP calls setport. Mecports does not support setting ports
;
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 ; point to which port
ld hl,hbport0 ; we want to set
or a
jr z,isport0
inc hl
isport0:ld c,(hl) ; get the associated CIO port
push hl
ld b,06h ; test if a valid cio
rst 08
pop hl
or a
ld a,(hl) ; get the associated CIO port
jr nz,seterr
ld (port),a ; save the valid port
call print
db 'Setting CIO device: ',0
jp diport
;
seterr: push hl
call print
db 'Unable to set CIO device: ',0
pop hl
ld a,(hl) ; get port we wanted to set
jp diport1
;
;****************************************************************************
;Video terminal sequences: these are for VT-100: Modify as you wish
;Cursor addressing:
cursadd:
ld hl,2 ; get parameters
add hl,sp
ex de,hl
call getparm ; in HL
inc hl
ld (row),hl ; row
call getparm
inc hl
ld (col),hl ; column
;
call print
db esc,'[',0
ld a,(row) ; row first
call cursconv
ld a,';'
call cout
ld a,(col) ; same for column
call cursconv
ld a,'H'
call cout
ret
;
cursconv:
ld b,a
xor a
ca1: add a,1
daa
djnz ca1
ld (num),a
and 0f0h
jr z,ca2
srl a
srl a
srl a
srl a
or '0'
call cout
ca2: ld a,(num)
and 0fh
or '0'
call cout
ret
;
row: ds 2 ; row
col: ds 2 ; column
num: ds 1
;
;Clear screen:
cls:
call print
db esc,"[H",esc,"[2J",0
ret
;
;Inverse video on:
invon:
call print
db esc,"[7m",0
ret
;
;Inverse video off:
invoff:
call print
db esc,"[m",0
ret
;
;Turn off cursor:
hide:
call print
db esc,'[?25l',0
ret
;
;Turn on cursor:
show:
call print
db esc,'[?25h',0
ret
;
;Save cursor position:
savecu:
call print
db esc,'[7',0
ret
;
;Restore cursor position:
rescu:
call print
db esc,'[8',0
ret
;
;****************************************************************************
;
;Service modem interrupt:
mint:
; ret ; unused
;
;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
;
; 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
;
;Wait(seconds) - entry point from C
wait: ld hl,2
add hl,sp
ex de,hl ; get delay size
call getparm
; fall thru to..
;Wait seconds in HL - entry point for this overlay
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
;
wait10: ld a,(outv) ; was ld b,outerval
ld b,a
wait11: ld de,(inv) ; was 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 - entry point from C
mswait: ld hl,2
add hl,sp
ex de,hl ; get delay size
call getparm
; fall thru to..
;Wait milliseconds in HL - entry point for this overlay
waithlms:
push de
w1ms0: ld de,(msv) ; was 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