mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
573 lines
12 KiB
Z80 Assembly
573 lines
12 KiB
Z80 Assembly
;-----------------------------------------------------------------------------
|
||
;
|
||
; Sample Overlay for ZMP (Z-Modem Program)
|
||
;
|
||
; Name ZMO-BLNK.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
|
||
; Modified to ZMP v1.5 standard rjm 25/3/89
|
||
;
|
||
;
|
||
;-----------------------------------------------------------------------------
|
||
;
|
||
;
|
||
; 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.)
|
||
;
|
||
;-----------------------------------------------------------------------------
|
||
;
|
||
;
|
||
; Notes on modifying this file:
|
||
;
|
||
; 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.
|
||
; Apart from defining modem functions, this file also defines terminal
|
||
; characteristics. Examples provided are 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 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 4 ; 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
|
||
|
||
|
||
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 (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
|
||
;
|
||
;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
|
||
; <== Insert your own code here
|
||
|
||
|
||
; <== End of your own code
|
||
|
||
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)
|
||
; <== Insert your own code here
|
||
|
||
|
||
; <== End of your own code
|
||
ret ; done
|
||
|
||
;Test for output ready: return TRUE (1) in HL if ok
|
||
mordy:
|
||
; <== Insert your own code here
|
||
|
||
; <== 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
|
||
|
||
|
||
; <== 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
|
||
|
||
ld hl,300 ; wait 300 mS
|
||
call waithlms
|
||
|
||
; <== End of your own code
|
||
ret
|
||
;
|
||
;Test UART flags for error: return TRUE (1) in HL if error.
|
||
mdmerr:
|
||
; <== Insert your own code here
|
||
|
||
; <== End of your own code
|
||
ld a,l ; set/clear Z
|
||
or a
|
||
ret
|
||
|
||
|
||
|
||
;Turn DTR ON
|
||
dtron:
|
||
; <== Insert your own code here
|
||
|
||
; <== End of your own code
|
||
ret
|
||
|
||
|
||
|
||
;Turn DTR OFF
|
||
dtroff:
|
||
; <== Insert your own code here
|
||
|
||
|
||
; <== 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 (BINARY 7 or 8)
|
||
call getparm
|
||
ld (stop),hl ; stop bits (BINARY 1 or 2)
|
||
|
||
|
||
; <== Insert your own code here
|
||
; using values below
|
||
ld (mspeed),a ; don't forget to load mspeed with the
|
||
; current brate value if the new rate is
|
||
; valid. See table of values below.
|
||
; <== End of your own code
|
||
ret
|
||
;--------------------------------------------------------------------------
|
||
|
||
stop: dw 1 ; stop bits
|
||
parity: dw 'N' ; parity
|
||
data: dw 8 ; data bits
|
||
brate: dw 7 ; 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
|
||
; 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)
|
||
|
||
; <== Insert your own code here
|
||
|
||
; <== End of your own code
|
||
ret
|
||
|
||
port: ds 1
|
||
|
||
|
||
;****************************************************************************
|
||
;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 1ah,0
|
||
ret
|
||
|
||
;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 ; 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
|
||
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:
|
||
dw overdrive ; .OVR etc. drive/user
|
||
dw overuser
|
||
|
||
|
||
if ($ - codebgn) gt ovsize
|
||
toobig: jp errval ; Overlay too large!
|
||
endif
|
||
|
||
end
|
||
|