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
/
BEEHIVE
/
COMMS
/
ZMP-OV16.ARC
/
ZMO-CX02.Z80
< prev
next >
Wrap
Text File
|
1991-02-02
|
19KB
|
873 lines
;-----------------------------------------------------------------------
;
; Colex 8xx overlay for ZMP (Z-Modem Program)
;
; Name ZMO-CX02.Z80
;
; Dated 12 November 1988
;
; Written by - Jon Saxton +61-2-807-6746
; Sydney, New South Wales.
;
; Upgraded to v1.4 standard and renamed to ZMO-CX02.Z80
; rjm 11/12/88
;
; The Colex 850 is an STD Bus Z80 computer running CP/M Plus.
; Serial I/O is driven by a Zilog 8530 SCC which is an extended
; version of the Z80 SIO.
;
; Whereas some of the code in this overlay is specific to the
; Colex and the 8530, the baud rate setting is not hardware-
; dependent and should work on any CP/M+ system which implements
; character device control in the same manner as that published
; by Digital Resarch in its sample CP/M+ BIOS.
;
; I know that the Morrow MD-10 does NOT follow the standard.
; This overlay will not work on a Colex 880 running TurboDOS.
;
;-----------------------------------------------------------------------
;
; 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-CLX+/h
; MLOAD ZMP.COM=ZMPX.COM,ZMO-CLX+.HEX
; or
; M80 =ZMOCLX.Z80
; RELHEX ZMOCLX
; MLOAD ZMP=ZMPX.COM,ZMO-CLX+.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 Aug 15, 88
;
;-----------------------------------------------------------------------
NO EQU 0
YES EQU NOT NO
; Values shown are for a Z8530 SCC
PORT equ 0H ; Base port (data or status)
MDCTL1 equ PORT ; Modem control port
MDDATP equ PORT+2 ; Modem data port
MDRCV equ 01h ; Modem receive ready
MDSND equ 04h ; Modem send ready bit
MDTXE equ 01h ; Modem send buffer empty, holding buffer empty
MDERR equ 70h ; Modem error bits
; User-set variables: ***********
;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
CLKSPD EQU 4 ; Processor clock speed in MHz
DEBUG EQU NO
USERDEF EQU 0145H ; Origin of this overlay. This address
; may change with subsequent revisions
; NOT user-set variables
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 ; DEBUG
ESC EQU 1BH
CTRLQ EQU 11H
CR EQU 0DH
LF EQU 0AH
BDOS EQU 5
; Jump table for the overlay: do NOT change this
CODEBGN EQU $
JUMPTAB: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: DS 0
; <== 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
mchin2:
; ld a,10h ;Select register 0
; out (MDCTL1),a
in a,(MDCTl1) ;Read register 0
and MDRCV ;Mask for receive data available
jr z,mchin2 ;Loop until a character arrives
in a,(MDDATP) ;Receive the character
; <== 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
mout2:
; ld a,10h ;Select register 0
; out (MDCTL1),a
in a,(MDCTl1) ;Read register 0
and MDSND ;Mask for transmit buffer empty
jr z,mout2
LD A,(HL) ;Instruction moved from a few lines up
out (MDDATP),a
; <== End of your own code
RET ; Done
; Test for output ready: return YES (1) in HL if ok
MORDY: DS 0
; <== Insert your own code here
ld hl,0 ;Assume no character available
; ld a,10h ;Select register 0
; out (MDCTL1),a
in a,(MDCTl1) ;Read register 0
and MDSND ;Mask for transmit buffer empty
jr status
; <== End of your own code
; Test for character at modem: return YES (1) in HL if so
MIRDY: DS 0
; <== Insert your own code here
ld hl,0 ;Assume no character available
; ld a,10h ;Select register 0
; out (MDCTL1),a
in a,(MDCTl1) ;Read register 0
and MDRCV ;Mask for receive data available
status:
jr z,noRDA
inc hl
noRDA:
; <== 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: DS 0
; <== Insert your own code here
ld a,5
out (MDCTL1),a
ld a,0F8H ; Send break, 8 bits, DTR, etc.
out (MDCTL1),a
LD HL,300 ; Wait 300 mS
CALL WAITHLMS
ld a,5
out (MDCTL1),a
ld a,(wr5) ; Restore preset parameters
out (MDCTL1),a
; <== End of your own code
RET
; Test UART flags for error: return YES (1) in HL if error
MDMERR: DS 0
; <== Insert your own code here
ld hl,0 ; Assume no error
ld a,1 ; Select register 1
out (MDCTL1),a
in a,(MDCTL1) ; Get error status bits
and MDERR
jr z,noErr
inc hl
noErr:
; <== End of your own code
LD A,L ; Set/clear Z
OR A
RET
; Turn DTR ON
DTRON: DS 0
; <== Insert your own code here
ld c,MDCTL1
ld b,lenCtl
ld hl,ctlStr
otir
; <== End of your own code
RET
; Turn DTR OFF
DTROFF: DS 0
; <== Insert your own code here
ld a,5
out (MDCTL1),a ; Send to the status port
ld a,68h ; Turn off DTR, send break
out (MDCTL1),a
; <== End of your own code
RET
; Initialise the SCC
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
; Colex 850 initialization -- Calls BIOS routines to set baud rate
; then re-programs the SCC for selected framing.
;
; Generic CP/M+ method of setting baud rate. This ONLY works if your
; CP/M+ BIOS follows the DRI model for character devices. If not then
; this whole overlay is pretty useless to you.
ld a,(BRATE) ; Get the selected value
cp 5 ; 1200 bps
jp z,OK1200
cp 6 ; 2400 bps
jp z,OK2400
cp 8 ; 9600 bps
jp z,OK9600
cp 9 ; 19200 bps
jp z,OK19200
jr SCC ; Program the SCC even if baud rate is wrong
initRet:
ld a,(BRATE)
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.
SCC:
; Set up data for SCC Write Register 4
ld b,44h ; Clock 16, 1 stop, no parity
ld a,(STOP) ; Set stop bits
cp 2 ; Set 2 if required
jr nz,chkOdd
set 3,b
chkOdd:
ld a,(PARITY) ; Set parity bits
cp 'O'
jr nz,chkEven
set 0,b ; Odd
jr setParity
chkEven:
cp 'E'
jr nz,setParity
set 0,b
set 1,b ; EVEN
setParity:
ld a,b
ld (wr4),a
; Set up data for SCC Write Registers 5 and 3
ld b,0EAh ; Assume DTR, transmit 8 bits, TxEn, RTS
ld c,0C1h ; Assume 8 bits on receive, RxEn
ld a,(DATA)
cp 7
jr nz,setDataBits
res 6,b ; 7 bits
res 6,c
setDataBits:
ld a,b
ld (wr5),a
ld a,c
ld (wr3),a
ld c,MDCTL1
ld b,lenCtl
ld hl,ctlStr
otir
; <== End of your own code
RET
;-----------------------------------------------------------------------
STOP: DW 1 ; Stop bits
PARITY: DW 'N' ; Parity
DATA: DW 8 ; Data bits
BRATE: DW 6 ; 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
; 115200 13
;
;-----------------------------------------------------------------------
;
; Video terminal sequences: these are for Datapoint 8227. 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 column
ld a,9 ; 8227 leadin
call rawOut ; No interference from CP/M
ld a,(col) ; Column first
call rawOut
ld a,(row) ; Row second
call rawOut
; <== end of your own code
RET
rawOut:
ld e,a
ld c,6
jp BDOS
ROW: DS 2 ; Row
COL: DS 2 ; Column
; Clear screen
CLS: CALL PRINT
DB 15h,17h,0
RET
; Inverse video on
INVON:
CALL PRINT
DB ESC,5,0
RET
;Inverse video off
INVOFF: CALL PRINT
DB ESC,4,0
RET
; Turn off cursor
HIDE: ld a,19h
call rawOut
RET
; Turn on cursor
SHOW: ld a,18h
call rawOut
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 registers
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
; 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 low
INC HL
LD D,(HL) ; Then hihi
INC HL ; Bump for next
EX DE,HL ; Result in HL, address still in DE
RET
OK300:
ld e,BD300
jp loadBd
OK1200:
ld e,BD1200
jp loadBd
OK2400:
ld e,BD2400
jp loadBd
OK9600:
ld e,BD9600
jp loadbd
OK19200:
ld e,BD19200
loadBd:
push ix
push iy
call BRSET
pop iy
pop ix
jp initRet
;------------------------------------------------------------------------------
;
; These routines set the baud rate for the SERIAL device.
;
; Provided that your CP/M+ BIOS follows the DRI model with respect
; to the character device table then you can very easily tailor
; this routine to your own modem port. The only thing you should
; need to change is the device name....
;
; Call BRSET with a baud rate selector in the E register and with
; the name of the modem device set up at label devName:
;
; Returns zero (and zero flag set) if no error. Returns carry flag
; true if device name is not in your BIOS's character device table.
;
; Jon Saxton,
; Tesseract RCPM+,
; AUSTRALIA
;
;------------------------------------------------------------------------------
; Baud rate selectors
bdNone equ 0 ; no baud rate associated with this device
bd50 equ 1 ; but don't use
bd75 equ 2 ; 75 baud
bd110 equ 3 ; 110 baud
bd134 equ 4 ; 134.5 baud
bd150 equ 5 ; 150 baud
bd300 equ 6 ; 300 baud
bd600 equ 7 ; 600 baud
bd1200 equ 8 ; 1200 baud
bd1800 equ 9 ; 1800 baud
bd2400 equ 10 ; 2400 baud
bd3600 equ 11 ; 3600 baud
bd4800 equ 12 ; 4800 baud
bd7200 equ 13 ; 7200 baud
bd9600 equ 14 ; 9600 baud
bd19200 equ 15 ; 19.2k baud
; Enter with required baud rate selector in E register
DEVTBL equ 20 ;BIOS function to return device table address
DEVINI equ 21 ;BIOS function to initialise a character device
BRSET:
; If we haven't already done so, find the address of the character device table
ld a,(gotIt) ;Have we done this already?
or a
jr z,haveIt ;Skip if we have been here already
push de ;Save baud rate selector
ld a,DEVTBL ;Get the device table address in HL
ld (bpbFn),a
ld de,bpb
ld c,50
call bdos
ld c,0FFh ;Initialise device number
dFind:
call dMatch ;Check current table entry
jp c,notFound ;Exit if device not listed
jp nz,dFind ;Continue if device not yet located
ld a,c ;Store device number for re-entry
ld (device),a
dec hl ;HL was pointing at the next device table
;entry so we step back to the baud rate
;field of the device we just scanned
ld (baudByte),hl ;and save the pointer for subsequent calls
xor a ;Signal that we have been here so we don't
ld (gotIt),a ;have to do this again
pop de ;Get new selector
haveIt:
ld hl,(baudByte) ;Point at baud rate selector
ld (hl),e ;Stuff the new one in the table
ld a,(device) ;Pick up the device number
ld (bpbC),a ;Put it into the parameter block
ld a,DEVINI ;Set the BIOS function number
ld (bpbFn),a
ld c,50 ;Call the BIOS via the BDOS
ld de,bpb
call BDOS
xor a ;Clear the error flag
ret
notFound:
pop de ;Restore the stack
ret ;Carry set, Zero reset
; Compare the character device name in the table with that for which we
; are searching. Return carry flag true if we are at the end of the
; device table. Return zero flag true if we find the name we're looking
; for. HL will be left pointing at the next device table entry. The
; current device number will be updated and returned in C.
dMatch:
inc c ;Step the device number
ld a,(hl) ;Check for end of table
or a
scf ;Exit with carry flag set if we have
ret z ;reached the end of the table
ld de,devName ;Point at the thing we're looking for
ld b,6 ;Number of bytes to compare
push hl ;Save pointer to current entry
dmLoop:
ld a,(de) ;Load byte from device name
sub (hl) ;Compare with byte from device table
jr nz,dmExit ;Break out if names are different
inc hl ;Step pointers
inc de
dec b
jr nz,dmLoop ;Loop until all bytes compared
dmExit:
pop hl ;Recover table pointer
push af ;Save flags while we update the device
ld de,8 ;table pointer
add hl,de
pop af ;Recover result for caller
or a ;Ensure carry flag is off
ret
devName:
defm 'SERIAL' ;Name of modem port device
gotIt:
defb 0FFh ;Initial entry flag
device:
defs 1 ;Storage for device number
baudByte:
defs 2 ;Holds pointer to baud rate selector
bpb:
bpbFn: defs 1 ;BIOS parameter block - function number
defs 1 ; - A register
bpbC: defs 6 ; - BC, DE and HL
ctlStr:
db 0 ; Select register
db 18h ; Throw out of mode
db 4 ; Select register
wr4: db 044h ; Set ASCII parameters (44=1, 4C=2)
db 3 ; Select register
wr3: db 0C1h ; Enable receive
db 5 ; Select register
wr5: db 0EAh ; Enable send, DTR, RTS
lenCtl equ $-ctlStr
;-----------------------------------------------------------------------
;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 is too large
ENDIF
END