home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
ftp.demon.co.uk-pub-cpm
/
amstrad
/
zmp15pcw.com
/
ZMP15PCW.MAC
< prev
next >
Wrap
Text File
|
1979-11-30
|
17KB
|
768 lines
;-----------------------------------------------------------------------
;
; Amstrad PCW8000 Overlay for ZMP (Z-Modem Program) Jul 6, 89
;
; Name ZMP15PCW.MAC
;
; Dated Jul 6, 1989
;
; Modified from ZMP-BLNK.Z80 by Nigel Dallard
;
; NOTE: As supplied in the ZMP15.LBR library, ZMP-BLNK.Z80
; would not assemble with M80. M80 objected to the hyphen in the
; filename, and to the labels WAITHLS and WAITHLMS which it
; thought were the same label. To enable M80 to assemble the file
; the name was changed to the current one, and the offending
; labels changed to WAITSHL and WAITMSHL.
; The conditional assembly portion at the end of the file was also
; removed since it included a call to a non-existant label. This
; does not affect the program assuming the code is within the
; specified size limitation.
; The code as supplied did not initialise the serial port on entry.
; The routine USERIN is used to call the INIT routine part way
; through to cure this.
;
; Modified from Nigel Dallard's code by Ian Macdonald
; (ianmacd@xs4all.nl) 16/6/95
;
; This slightly modified version produced 28/6/95 for use with EMU,
; the VT100 emulator. When run with EMU in the background, the
; 16/6/95 version causes a crash because both programs make use of
; the Z80 alternate register set for screen display.
; If you wish to use EMU, set the EMU equate to YES prior to
; assembly.
;
;------------------------------------------------------------------------
;
; System-dependent code overlay for ZMODEM
;
; Assemble as follows:
;
; First edit this file and change the FAXLINK and SPRINTER equates
; to reflect your hardware (YES or NO). Save the file and then
; execute the following sequence of commands:
;
; M80 =ZMP15PCW
; RELHEX ZMP15PCW
; MLOAD ZMP.COM=ZMPX.COM,ZMP15PCW.HEX
;
; (Don't use L80 without changing the source for assembly as a CSEG
; file.)
;
; Then add Stephen Younger's interrupt driven RSX as follows:
;
; First edit QTERMRSX.ASM to change the ZMP equate to YES and, if
; necessary, alter the FAXLINK equate to YES. Then execute the
; following sequence of commands:
;
; RMAC QTERMRSX $$PZ
; LINK QTERMRSX[OP NR]
; ERA ZMPRSX.RSX
; REN ZMPRSX.RSX=QTERMRSX.PRL
; GENCOM ZMP ZMPRSX
;
;
;
;-----------------------------------------------------------------------
;
; 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.
;
; 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.
;
;-----------------------------------------------------------------------
;
NO EQU 0
YES EQU NOT NO
;
;
; User-set variables:
;
FAXLINK equ NO ; set YES for Fax Link, NO for CPS8256
SPRINTER equ NO ; set YES for Cirtech Sprinter
EMU equ YES ; set YES if the EMU VT100 emulator will be used
rsxbas equ 0006h ; to base offsets for SI calls
rsxini equ 001bh ; offset for initializing RSX
rsxxit equ 001eh ; offset to quit from RSX
txrdy equ 4 ; transmit buffer clear mask
conout equ 0fc0ch ; BIOS CONOUT function
userf equ 0fc5ah ; BIOS USERF function
IF FAXLINK
datap equ 0c8h ; Values with Fax link fitted
statp equ 0c9h ; ~~~~~~~~~~~~~~~
ELSE
datap equ 0e0h ; Values with CPS8256 fitted
statp equ 0e1h ; ~~~~~~~~~~~~~~
ENDIF
IF SPRINTER
clkspd equ 6 ; value with Sprinter 6 - otherwise 3
; (PCW closer to 3 Mhz than 4)
ELSE
clkspd equ 3 ; Processor clock speed in MHz
ENDIF
DEBUG EQU NO ; 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
;
;-----------------------------------------------------------------------
;
; 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 ; Maximum 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
;
;-----------------------------------------------------------------------
;
;Jump table for the overlay: do NOT change this
;
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
JP SETPORT ; Set the modem port being used
;
; 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: CALL PRINT ; print message
DB CR,LF,'Press [EXTRA] + [PTR] for a screen dump.',CR,LF,0
;
SPARE: RET
;
; User-defined entry routine: used by ND to initialise UART on entry
; Code to initialise RSX added by IM
;
USERIN: CALL INIT2
rsxin: ld de,rsxini ; offset for RSXinit
grsxbs: ld hl,(rsxbas) ; get RSX base address
ld l,0
add hl,de
jp (hl) ; execute
;
; User-defined exit routine: leave empty if not needed
;
USEROUT:
rsxout: ld de,rsxxit ; offset for quit routine - A MUST
jr grsxbs ; get RSX base address and execute
;
; Get a character from the modem: return in HL
;
MCHIN: ;PUSH BC
;
; <== Start of user-defined code
;
exx ; save BC
call 0000 ; RSX will fill in the correct address
exx ; restore BC
;
; <== End of user-defined 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)
;
; <== Start of user-defined code
;
out (datap),a
;
; <== End of user-defined code
;
RET ; Done
;
;
;Test for output ready: return TRUE (1) in HL if ok
;
MORDY:
;
; <== Start of user-defined code
;
in a,(statp)
and txrdy
ld hl,0
ret z ; not ready
inc l
; <== End of user-defined code
RET
;
;
MIRDY:
;
; <== Start of user-defined code
;
jp 0000 ; RSX will fill in the correct address
;
; <== End of user-defined code
;RET
;
; Send a break to the modem: leave empty if your system can't do it
;
SNDBRK:
;
; <== Start of user-defined code
;
; The PCW BDOS/BIOS doesn't allow you to send a BREAK (ND)
; True, but we can make our own (IM)
call getr5 ; get DART wreg5 bit pattern in b
set 4,b ; set break
ld a,5
out (statp),a ; send to wreg5
ld a,b
out (statp),a
ld hl,300
call waitmshl ; make the break last 300 msecs.
ebreak: call getr5
ld a,5
out (statp),a
ld a,b
out (statp),a
;
; <== End of user-defined code
;
RET
getr5: call getpara ; ext BIOS call
ld a,l ; put Tx Data bit size into a
and 3 ; 0=8b,1=5b,2=6b,3=7b
ld c,a
ld b,0
ld hl,wreg5
add hl,bc
ld b,(hl) ; get bit pattern from lookup table
ret
wreg5: db 11101010b ; 8 Data bits Tx DTR ON
db 10001010b ; 5 Data bits Tx
db 11001010b ; 6 Data bits Tx
db 10101010b ; 7 Data bits Tx
;
; Test UART flags for error: return TRUE (1) in HL if error.
;
MDMERR:
;
; <== Start of user-defined code
;
;LD HL,0 ; Serial errors are dealt with by BDOS
xor a
;
; <== End of user-defined code
;
;LD A,L ; Set/clear Z
;OR A
RET
;
;
; Turn DTR ON
;
DTRON:
;
; <== Start of user-defined code
;
LD A,80H ; ask the BIOS to drop DTR
jp sioset
; <== End of user-defined code
;
;RET
;
;
; Turn DTR OFF
;
DTROFF:
;
; <== Start of user-defined code
;
LD A,7FH ; ask BIOS to raise DTR
jp sioset
;
; <== End of user-defined 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)
;
; <== Start of user-defined code
;
; 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.
;
INIT2: ld hl,(conout+1) ; get BIOS CONOUT jump
ld (outadd+1),hl ; store it in print routine
LD HL,(BRATE) ; HL = baud-rate code
ADD HL,HL ; double it
LD BC,BRTBL ; BC = base of baud-rate look-up table
ADD HL,BC ; HL points to entry in look-up table
LD E,(HL) ; E = encoded tx baud rate
INC HL
LD D,(HL) ; D = encoded rx baud rate
LD A,E ; encoded tx baud rate of 0 => not supported
OR A
JR NZ,SETBD ; if not supported, print message & leave
CALL PRINT ; baud rate set as present.
DB 'Baud Rate not supported.',CR,LF,0
JR CHKPAR
SETBD: EX DE,HL ; HL = encoded baud-rates
CALL BAUD ; let BIOS set the baud-rate
LD A,(BRATE) ; adjust the ZMP modem speed variable
LD (MSPEED),A
JR CHKPAR ; go on to set the rest of the uart parameters
BRTBL: DB 03H,03H ; 110 baud
DB 06H,06H ; 300 baud
DB 08H,02H ; 450 baud [ actually used for 7512 ]
DB 07H,07H ; 600 baud
DB 02H,08H ; 710 baud [ actually used for 1275 ]
DB 08H,08H ; 1200 baud
DB 0AH,0AH ; 2400 baud
DB 0CH,0CH ; 4800 baud
DB 0EH,0EH ; 9600 baud
IF NOT FAXLINK
DB 0FH,0FH ; 19200 baud
DB 00H,00H ; 38400 baud
ELSE
DB 00H,00H ; 19200 baud
DB 0FH,0FH ; 38400 baud
ENDIF
DB 00H,00H ; 57600 baud
DB 00H,00H ; 76800 baud
CHKPAR: LD E,0 ; no parity => E = 0
LD A,(PARITY) ; A = parity value
CP 'N'
JR z,chkdata
NOTNONE:inc e ; odd parity => E = 1
CP 'O'
JR z,chkdata
NOTODD: inc e ; even parity => E = 2
CHKDATA:LD A,(DATA) ; A = number of data bits
LD H,A ; H = rx data bits
LD L,A ; L = tx data bits
LD A,(STOP) ; A = number of stop bits
dec a
JR NZ,STOP2
ld d,a ; 1 stop bit => D = 0
JR SETSIO
STOP2: LD D,2 ; 2 stop bits => D = 2
SETSIO: LD A,0FEH ; sio mode = interrupt, no handshake
jr sioset ; let BIOS set up the sio port
;RET
BAUD: CALL PARMS ; set the baud rate
DW 00B9H ; via extended BIOS function B9h
RET
SIOSET: CALL PARMS ; set the sio parameters
DW 00B6H ; via extended BIOS function B6h
RET
getpara: call parms ; get the current settings
dw 0bch ; via extended BIOS function B9h
ret
PARMS: JP userf ; BIOS entry point to set sio parameters
; and baud rate. The code self-modifies
; itself to provide the correct address.
;
; <== End of user-defined 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
;
;-----------------------------------------------------------------------
;
; Set the port. ZMP supplies either 0 or 1 as a parameter. If you only
; have 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 twice -- once for each port value -- on
; initialisation.
;
SETPORT:LD HL,2 ; Get port number
ADD HL,SP
EX DE,HL
CALL GETPARM ; In HL (values are 0 and 1)
;
; <== Start of user defined code
;
; Only one serial port on the PCW.
;
; <== End of user defined code
;
RET
;
PORT: DS 1
;-----------------------------------------------------------------------
;
; Video terminal sequences: these are for Amstrad PCW8000 series
;
; 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
;
; <== Start of user-defined code
;
CALL PRINT
DB ESC,'Y',0 ; leadin
LD A,(ROW) ; Row first
ADD A,32 ; Add offset
CALL COUT
LD A,(COL) ; Same for column
ADD A,32
jr COUT
;
; <== End of user-defined code
;
;RET
;
ROW: DS 2 ; Row
COL: DS 2 ; Column
;
; Clear screen
;
CLS: CALL PRINT
DB ESC,'E',ESC,'H',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,'f',0
RET
;
; Turn on cursor
;
SHOW: CALL PRINT
DB ESC,'e',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 WAITMSHL
DEC BC ; Loop till done
LD A,B
OR C
JR NZ,MRD1
XOR A
ld h,a
ld l,a ; None there, result=0
;
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:
IF EMU
PUSH BC ; Save registers
PUSH DE
PUSH HL
ELSE
exx ; register switch is much faster than all those
; speed killing stack operations (but fatal with EMU!)
ENDIF
ld c,a ; Character to E
outadd: call 0000 ; Print it (via the BIOS - BDOS was too slow)
IF EMU
POP HL
POP DE
POP BC
ELSE
exx
ENDIF
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
;
WAITSHL: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
;
WAITMSHL: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 HIGH
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
END
----------------------------------------------------
;
; Amstrad PCW8000 Overlay for ZMP (Z-Modem Program)