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
/
OSBORNE
/
OSBZMP.ARK
/
ZMOOS01.Z80
< prev
next >
Wrap
Text File
|
1989-09-27
|
19KB
|
791 lines
; OSBORNE 1 Overlay for ZMP (Z-Modem Program)
; Name ZMOOS01.Z80
; Dated 20 NOV 1990
; Written by -
; Klaus Schauer
; Auf den Kempen 31
; 4052 Korschenbroich 2
; Germany (West)
; global informations
; set baud rate to 300, 600, 1200 or 2400
; The OSBORNE 1 switchs between 300/1200 and 600/1200 Baud with
; software. If you would use three or four baud rates you must
; build in a hardware switch. See OSBORNE 1 technical notes.
; I made an hardware extention for the MODEM port that switch
; between the four baud rate.
; Also it generate an correct RS-232 interface.
; NOTE: The extention works with TRANS-MODEM 2400 or modems with
; the INTEL Modem Chip Set 89024. For other modems: it is nessecary
; that the modem send HS (PIN 12) for a short time after the
; command ATZ from the OSBORNE 1.
; using the MODEM port
; To use the MODEM port an hardware extention is needed.
; Contact me for the schematics and layout.
; BREAK, drops RTS (used for DISCONNECT) and the automatic baud
; selection (300, 600, 1200, 2400 bps) are only available on the MODEM
; port.
; global constants
false equ 0
true equ not false
LF equ 0Ah ; Linefeed
CR equ 0Dh ; Carriage Return
CLRSCR equ 1Ah ; Clear Screen
ESC equ 1Bh ; Escape
ctrlq equ 11h
; BDOS constants
CONOUT equ 2 ; Console Char Out
INOUT equ 6 ; Direct Input/Output
brkbit equ 01100000b ; bits to set to send break
; User-set variables
clkspd equ 4 ; Processor clock speed in MHz
debug equ false ; to allow debugging of overlay with Z8E etc.
overdrive equ 'A' ; Drive to find overlay files on ('A'-'P')
overuser equ 0 ; User area to find files
; NOT user-set variables
boot equ 0000 ; CP/M Boot address
jtabl equ boot+1 ; CP/M Jump Table address
bdos equ 0005
mspeed equ 003Ch ; location of current baud rate.
tpa equ 0100h
start equ 010Bh ; ZMP's start address
userdef equ 0145h ; origin of this overlay
; This address should not change with
; subsequent revisions.
ovsize equ 0400h ; max size of this overlay
mdctlp equ 2A00h ; Status Register for Serial Port
mddatp equ mdctlp+1 ; Data Register for Serial Port
curs equ 0EF5Ah ; CBIOS addr for current cursor position
; (curs+1) (curs)
; -------- --------
; 1111RRRR RCCCCCCC R = row, C = column
.z80 ; use z80 code
aseg ; absolute
org tpa
jp initmd ;init the modem routines
if debug
org 100h ; so you can debug it with cebug, zsid, etc
else
org userdef
endif
codebgn equ $
;Jump table for the overlay: do NOT change this
jump_tab:
jp scrnpr ; screen print
jp mrd ; modem read with timeout
mchin: jp $-$ ; get a character from modem
; patched to OSIN by INITMD
mchout: jp $-$ ; send a character to the modem
; patched to OSOUT by INITMD
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
; Overlay data
modctb: DEFB 15H ; Modem control byte
; MODEM port 8N1
; 16H = 300 bps / 600 bps
; 15H = 1200 bps / 2400 bps
; RS-232 port (V.24) 8N1
; 56H = 300 bps / 600 bps
; 55H = 1200 bps / 2400 bps
port: ds 1 ; (port) = 0: Modem port active
; (port) = 1: RS-232 port active
; Init modem port routines before running ZMP
initmd: LD HL,(BDOS+1) ; FIND START OF BDOS
LD DE,-0100H ; GO TO FIRST PAGE AHEAD OF BDOS
ADD HL,DE ; HL NOW POSITIONED ONE PAGE BELOW BDOS
PUSH HL ; SAVE THE ADDRESS
LD DE,BDJ ; POINT TO OUR ROUTINE TO PUT THERE
LD BC,CDLEN+2 ; SET LENGTH OF CODE
EX DE,HL
LDIR ; copy BDJ:, OSIN:, OSOUT: and OSTAT
; under BDOS. These routines must in a memory
; location above 4000h
LD HL,(BDOS+1) ; GET BDOS ADDRESS BACK ONCE MORE
POP DE ; GET THE STARTING ADDRESS OFF STACK
PUSH DE ; PUT IT BACK ON THE STACK
INC DE ; POINT TO ADDRESS POSITION
EX DE,HL ; PUT INTO 'HL'
LD (HL),E ; STORE 'LSP' ADDRESS
INC HL ; GET 'LSP' LOCATION
LD (HL),D ; STORE 'MSP' ADDRESS
POP HL ; GET THE ADDRESS BACK ONCE MORE
LD (BDOS+1),HL ; NEW ADDRESS TO PROTECT FOR OVERWRITE
LD DE,OSIN-BDJ ; GET THE LENGTH OF ROUTINE TO MOVE
ADD HL,DE ; COMUTE ADDRESS OF THE 'OSIN' ROUTINE
LD (mchin+1),HL ; PATCH CALL FOR "GET CHAR." ROUTINE
LD DE,OSOUT-OSIN
ADD HL,DE
LD (mchout+1),HL ; PATCH jump to "SEND CHAR." ROUTINE
LD DE,osout1-OSOUT
ADD HL,DE
LD (smcall+1),HL ; PATCH jump to "SEND CHAR." ROUTINE
LD DE,OSTAT-OSOUT1
ADD HL,DE
LD (mordy+1),HL ; PATCH CALL FOR "GET STATUS" ROUTINE
ld (mirdy+1),HL
ld (mdmerr+1),HL
ld (smsend+1),HL
JP START ; Run ZMP
;Screen print function
scrnpr:
ret
spare:
ret
; User-defined entry routine: leave empty if not needed
userin:
ret
; User-defined exit routine: leave empty if not needed
userout:
ret
;Test for output ready: return TRUE (1) in HL if ok
mordy: call $-$ ; get port status
; patched to OSTAT by INITMD
and 00000010b ; extract bit 1
rrca ; move bit 1 in bit 0
ld l,a
ld h,0
or a ; set/clear Z-flag
ret
;Test for character at modem: return TRUE (1) in HL if so
mirdy: call $-$ ; get port status
; patched to OSTAT by INITMD
and 00000001b ; extract bit 0
ld l,a
ld h,0
or a ; set/clear Z-flag
ret
;Send a BREAK to the modem
sndbrk: ld a,(port)
or a
jr nz,nobrk ; jump if Port B is active (RS-232)
ld a,(modctb) ; load Modem Control Byte
or brkbit ; set Break bits
call oset
ld hl,300 ; wait 300 mS
call waitms
ld a,(modctb)
jp oset
nobrk: call print ; no Break on RS-232 port
CR,LF,'No ',0
ret
;Test UART flags for error: return TRUE (1) in HL if error.
mdmerr: call $-$ ; get port status
; patched to OSTAT by INITMD
and 01110000b ; extract error bits
; bit 4: Framing Error (FE)
; bit 5: Receiver Overrun (OVRN)
; bit 6: Parity Error (PE)
ld h,0
ld l,0
ret z ; return if no error (Z-flag = High)
ld l,1
ret ; return with error (Z-flag = Low)
;Turn DTR ON
dtron: ld a,(port)
or a
ret nz ; return if Port B is selected (RS-232)
; RS-232 port only active if /RTS = high
ld a,(modctb)
res 6,a ; 6850 ACIA's /RTS = low
jp oset
;Turn DTR OFF
dtroff: ld a,(modctb)
set 6,a ; 6850 ACIA's /RTS = high
jp oset
;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,(data) ; load data bits
cp 7 ; seven data bits ?
ld c,0
jr z,data7
set 4,c ; set data length to 8
ld a,(parity) ; load parity
cp 'N' ; no parity ?
jr nz,par1
ld a,(stop) ; load stop bits
cp 1 ; one stop bit ?
jr nz,sbaud ; control byte now: xxx100xxb (8N2)
set 2,c
jr sbaud ; control byte now: xxx101xxb (8N1)
par1: cp 'O' ; odd parity ?
jr nz,par2
set 2,c ; set odd parity
par2: ld a,(stop) ; load stop bits
cp 1 ; one stop bit ?
jp nz,seterr ; print Error: (8E2) and (8O2) not supported
set 3,c
jr sbaud ; control byte now: xxx110xxb (8E1)
; or: xxx111xxb (8O1)
data7: ld a,(stop) ; load stop bits
cp 1 ; one stop bit ?
jr nz,par3 ; jump if two stop bits
set 3,c ; set one stop bit
par3: ld a,(parity) ; load parity
cp 'N' ; no parity ?
jp z,seterr ; print Error: (7N1) and (7N2) not supported
cp 'O' ; odd parity ?
jr nz,sbaud ; jump if even parity
; control byte now: xxx000xxb (7E2)
; or: xxx010xxb (7E1)
set 2,c ; set odd parity
; control byte now: xxx001xxb (7O2)
; or: xxx011xxb (7O1)
sbaud: ld a,(port)
or a
ld a,(brate)
jp z,nbaud ; jump if port A is selected
; set baud rate on RS-232 port
; user must toggle 300 <> 600 and 1200 <> 2400 bps with hardware switch
ld e,a ; set baud rate
ld d,0
ld hl,bratev ; load bratev address in HL
add hl,de ; add (brate): HL pointed to baud code
ld a,(hl) ; baud rate bits in A, A = 0 if not supp.
or a
ret z ; return with Error: baud rate not supported
ld b,a
ld a,(modctb)
and 11100000b ; strip out baud rate data, parity and
; stop bits
or c ; set data, parity and stop bits
or b ; set baud rate bits
ld (modctb),a
call oset ; send new status byte to the serial port
ld a,(brate) ; load mspeed with the current brate value
ld (mspeed),a ; if the new rate is valid.
; See table of values below.
ret
seterr: call print
db ' ## Entry Error ##',0
ld hl,2
call waithls
ret
smres: db 'ATZ',CR,0
smdp1: db 'AT&P1',CR,0
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
;
bratev: db 0 ; 110 0
db 00000010b ; 300 1
db 0 ; 450 2
db 00000010b ; 600 3
db 0 ; 710 4
db 00000001b ; 1200 5
db 00000001b ; 2400 6
db 0 ; 4800 7
db 0 ; 9600 8
db 0 ; 19200 9
db 0 ; 38400 10
db 0 ; 57600 11
db 0 ; 76800 12
; set baud rate an Modem port (with hardware extention)
nbaud: LD HL,MSPEED ; HL = mspeed
CP (HL) ; ? (brate) = (MSPEED)
jp Z,stend ; if equeal return
CP 1 ; 300 bps ?
JR Z,OK300
cp 3 ; 600 bps ?
jr z,ok600
CP 5 ; 1200 bps ?
JR Z,OK1200
CP 6 ; 2400 bps ?
JR Z,OK2400
XOR A ; Entry error, clear A and flags
or a ; set Z-flag, ZMP prints Error message
RET
OK2400: CALL ST2400
JP STBAUD
OK300: CALL ST2400
CALL ST300
CALL PAUSE ; pause
JP STBAUD
ok600: call st2400
LD A,(MODCTB) ; Last 6850 control byte
and 11111100b ; strip out baud rate bits
or 00000010b ; set baud rate bits to 300 bps
LD (MODCTB),A ; set new baud rate
CALL OSET ; set OSBORNE 1 to 600 bps
CALL PAUSE ; pause
jp stbaud
OK1200: CALL ST2400
CALL ST300
LD A,(MODCTB) ; Last 6850 control byte
and 11111100b ; strip out baud rate bits
or 00000001b ; set baud rate bits to 1200 bps
LD (MODCTB),A ; set new baud rate
CALL OSET ; set OSBORNE 1 to 1200 bps
CALL PAUSE ; pause
; fall in STBAUD
STBAUD: CALL MODP1 ; set puls dialing mode
stend: xor a ; clear A and flags
LD A,(brate)
RET
ST2400: LD (MSPEED),A ; save new baud rate
LD A,(MODCTB) ; Last 6850 control byte
and 11100000b ; strip out baud rate data, parity and
; stop bits
or c ; set data, parity and stop bits
or 00000001b ; set baud rate bits to 1200 bps
LD (MODCTB),A ; set new baud rate
CALL OSET ; set OSBORNE 1 to 1200 bps
CALL MDRES ; first modem reset + pause
JP MDRES ; second modem reset
; set OSBORNE 1 to 2400 bps (hardware switch)
ST300: LD A,(MODCTB) ; Last 6850 control byte
and 11111100b ; strip out baud rate bits
or 00000010b ; set baud rate bits to 300 bps
LD (MODCTB),A ; set new baud rate
CALL OSET ; set OSBORNE 1 to 300 bps
; fall in modem reset + pause
MDRES: LD HL,SMRES ; modem reset (send ATZ to modem)
CALL SMSEND
; fall in PAUSE
PAUSE: LD hl,1500 ; wait 1500 ms (1.5 sec)
jp waitms ; and return
MODP1: LD HL,SMDP1 ; send AT&P1 to Modem
CALL SMSEND
JP PAUSE ; pause
; Smartmodem utility routine: send string to modem
SMSEND: CALL $-$ ; get port status
bit 1,a ; test flag Transmit Data Reg. Empty (TDRE)
JR Z,smsend ; wait for modem send ready
LD A,(HL) ; FETCH NEXT CHARACTER
INC HL
OR A ; END?
RET Z ; DONE IF SO
smcall: CALL $-$ ; send char to serial port
; patched to OSOUT1 by INITMD
JR SMSEND
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
ld (port),a
or a
ld a,(modctb)
jr nz, v24 ; jump if port 1 requested
res 6,a ; 6850 ACIA's /RTS = low: Modem port active
ld (modctb),a
jp oset
v24: set 6,a ; 6850 ACIA's /RTS = high: RS-232 port active
ld (modctb),a
jp oset
;Video terminal sequences
;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
ld a,ESC
call cout
ld a,'='
call cout
ld a,(row) ; row first
add a,' ' ; add offset
call cout
ld a,(col) ; sane for column
add a,' '
jp cout ; print column and return
row: ds 2 ; row
col: ds 2 ; column
;Clear screen
cls: ld a,CLRSCR
jp cout ; clear screen and return
;Dim video
invon: ld a,ESC
call cout
ld a,')'
jp cout ; print and return
;Bright video
invoff: ld a,ESC
call cout
ld a,'('
jp cout ; print and return
;Turn off cursor:
hide: ret
;Turn on cursor:
show: ret
;Save cursor position:
savecu: LD HL,(CURS) ; load curent cursor position
; H L
; -------- --------
; 1111RRRR RCCCCCCC R=row, C=column
LD A,H
AND 0FH ; Strip out bits 4-7
OR A ; Clear C-flag
RL L ; Bit 7 in C-flag, bit 0 = 0
RLA ; Now bit 7 from L in bit 0
RRC L ; L = 0CCCCCCC C=column
LD H,A ; H = 000RRRRR R=row
LD (ccurs),HL ; Store curent cursor position in CCURS
ret
ccurs: db 0,0 ; saved cursur position
; (ccurs) = column position
; (ccurs+1) = row position
;Restore cursor position:
rescu: ld a,ESC
call cout
ld a,'='
call cout
ld a,(ccurs+1) ; row first
add a,' ' ; add offset
call cout
ld a,(ccurs) ; sane for column
add a,' '
jp cout ; print column and return
;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 waitms
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
waitms:
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
; Osborne Serial Port Input/Output routines
; stuff the control register on the 6850
OSET: LD C,A
LD HL,(JTABL) ; load BIOS+3 adress, C = (MODCTB)
LD L,3CH ; SPECIAL OSBORNE ROUTINE (SBAUD: E13C)
JP (HL) ; BRANCH TO IT
; ROUTINES THAT GET PLACED JUST UNDER 'BDOS' OVERLAYING 'CCP'
BDJ: JP $-$ ; THIS GETS PATCHED TO JUMP TO BDOS ENTRY
;Get a character from the modem: return in HL
osin: DI ; DISABLE INTERRUPTS
OUT (0),A ; SWITCH TO ALTERNATE PAGE
LD A,(MDDATP) ; GET DATA BYTE
OUT (1),A ; SWITCH PAGES BACK
EI ; RE-ENABLE INTERRUPTS
ld l,a ; put in HL
ld h,0
or a ; set/clear Z
RET
;Send a character to the modem
osout: ld hl,2 ; get the character
add hl,sp
ld a,(hl)
osout1: DI ; DISABLE INTERRUPTS
OUT (0),A ; SWITDH TO ALTERNATE PAGE
LD (MDDATP),A ; SEND DATA BYTE
OUT (1),A ; SWITCH PAGES BACK
EI ; RE-ENABLE INTERRUPTS
RET
;Get status byte from the serial port
ostat: DI ; DISABLE INTERRUPTS
OUT (0),A ; SWITCH TO ALTERNATE PAGE
LD A,(MDCTLP) ; GET STATUS BYTE
OUT (1),A ; SWITCH PAGES BACK
EI ; RE-ENABLE INTERRUPTS
RET
CDLEN EQU $-BDJ ; LENGTH OF CODE TO COPY
if ($ - codebgn) gt ovsize
toobig: jp errval ; Overlay too large!
endif
end