Commodore 128 CP/M v3.0
External drive support
;
;
title 'C128 external Disk drive support 28 Apr 86'
;
; This program contains the stubs for bringing up the C128 CP/M
; for the first time.
;
; The method used to stub the system I/O is to send the
; operation request to the serial port as a command and
; recieve responce from the serial channel.
;
; The commands supported are:
;
; CMD: 'I' ; input keyboard char
; RSP: xx ; returns keybord char or 00 if none
;
; CMD 'O'xx ; send char xx to display
; RSP: xx ; echo character
;
; CMD: Rttss ; read sector of data adr by track (tt) sector (ss)
; RSP: xx..yy ; returns 128 bytes of data plus a check sum
;
; CMD: Wttssxx..yy ; write sector of data, sent with a check sum
; ; to (xx..yy) adr by track (tt) sector (ss)
; RSP: xx ; xx=00 if no error
;
page
maclib cpm3
maclib z80
maclib cxequ
public ?int65,?in65,?ins65,?out65,?outs65
extrn ?intbd
; Utility routines in standard BIOS
extrn ?pmsg ; print message @<HL> up to 00
; saves <BC> & <DE>
extrn ?pdec ; print binary number in <A> from 0 to 99.
extrn ?pderr ; print BIOS disk error header
extrn ?conin,?cono ; con in and out
extrn ?const ; get console status
;
; drive table
;
public @dtbl
extrn cmdsk0,cmdsk1,cmdsk2,cmdsk3,cmdsk4,RMdsk
page
;
; DRVTBL.ASM
;
CSEG ; place code in common memory
@dtbl:
dw cmdsk0 ;* drive A 1541/1571
dw cmdsk1 ;* drive B 1541/1571
dw cmdsk2 ;* drive C 1541/1571
dw cmdsk3 ;* drive D 1541/1571
dw cmdsk4 ;* drive E shares drive A
dw 0 ;* drive F
dw 0 ;* drive G
if EXTSYS
dw @fdsd0 ;* drive H (external RS232)
else
dw 0 ;* drive H
endif
dw 0 ;* drive I
dw 0 ;* drive J
dw 0 ;* drive K
dw 0 ;* drive L
dw RMdsk ;* drive M Memory Disk (RAM disk)
dw 0 ;* drive N
dw 0 ;* drive O
dw 0 ;* drive P
if EXTSYS
CSEG
;
; Extended Disk Parameter Headers (XPDHs)
;
dw fd$write
dw fd$read
dw fd$login
dw fd$init
db 0 ; relative drive zero
db 0 ; format type byte
@fdsd0:
dph sk128sssd,dpb$8$sssd
;
; DPB FOR 8 IBM 3740 format ( 243K )
;
dpb$8$sssd: dpb 128,26,77,1024,64,2
sk128sssd:
skew 26,6,1
page
;
; send an illegial command, should get a period back, meaning
; that the the command was bad. at this point extrnal system
; is ready to receive a valid command.
;
CSEG
resync:
mvi c,0dh
call send$c
call get
cpi '.'
jrnz resync
mvi c,'O'
call send$c
mvi c,07 ; beep the bell
call send$c
call get ; should be a bell code
cpi 07
rz
call get
jr resync
;
; CXDISK.ASM
;
;
;
;
dseg
fd$read:
mvi a,10
sta error$count ; set retrys to 10
retry$read:
lxi h,retry$read
push h ; save retry address on the stack
mvi a,'R'
call set$up$dsk ; send command, track and sector
read$loop:
call get
if banked
call put$byte$de$bank ; save byte disk bank
mov a,c
else
mov m,a
endif
inx h
call do$sum
jrnz read$loop
call get
lda check$sum
cmp c
jrnz dsk$error
pop h ; remove retry address
xra a ; A=0 (no errors)
;
;
fd$init:
fd$login:
ret
;
;
;
if banked
cseg
put$byte$de$bank:
lda force$map ; read current MMU configuration
stax d ; force to preconfig reg adr in DE
mov m,c ; save C in proper bank
sta force$map ; force the old bank back
ret
endif
page
;
;
;
dseg
dsk$error:
call resync
lda error$count
dcr a
sta error$count
rnz ; return to retry address
inr a ; A=1 if hard error
pop h ; remove retry address on error
ret
error$count: db 0
page
;
;
;
dseg
fd$write:
mvi a,10
sta error$count ; set retrys to 10
retry$write:
lxi h,retry$write
push h
mvi a,'W'
call set$up$dsk ; send command, track and sector
write$loop:
if banked
call get$byte$de$bank
else
mov c,m
endif
call send$c ; leaves sent char in A
inx h
call do$sum
jrnz write$loop
lda check$sum
call send$a
call get
ora a ; A=0 if no errors
jrnz dsk$error
pop h ; remove error address
ret ; A=0 (no errors)
if banked
cseg
get$byte$de$bank:
lda force$map ; read current MMU configuration
stax d ; set current disk bank (in DE)
mov c,m
sta force$map ; write current MMU conf back
ret
endif
page
;
; compute check sum and adjust byte count
;
dseg
do$sum:
mov b,a
lda check$sum ; get the current sum
add b ; add in new byte
sta check$sum ; save new sum
lda count ; get byte count
dcr a ; one less to get
sta count ; save for later
ret ; zero flag set if DONE
check$sum: db 0
count: db 0
;
; send the command, track and sector to the external system
; set count to 128 bytes, clear the checksum and set HL to
; the DMA address
;
set$up$dsk:
call send$a ; send the comand
lda @trk
call send$a ; send the track
lda @sect
call send$a ; send the sector
xra a
sta check$sum
mvi a,80h
sta count ; transfer 128 bytes
lhld @dma ; HL = current DMA address
if banked
lxi d,bank$0 ; start by pointing to bank 0
lda @dbnk ; get the current disk I/O bank
ora a ; is it set to bank 0
rz ; yes, return
inx d ; no, point to bank 1
endif
ret
page
;==========================================================
; CHARACTOR INITILIZATION ROUTINES
;==========================================================
;
;
;
dseg
;
; set external system com rate to 19.2 K baud
;
?int65:
init$ext:
lhld usart$adr
mov b,h
mov c,l
inx b
inx b ; point to command reg
mvi a,cmd$init
outp a
inx b ; point to control reg
mvi a,cntr$init$19200 ; baud rate equ 19200
outp a
dcx b ; (02)
dcx b ; (01)
inp a ; read status
dcx b ; (00)
inp a ; read hung data
ret
page
;==========================================================
; CHARACTOR INPUT ROUTINES
;==========================================================
;
;
;
dseg
?in65: ; character input
call ?ins65 ; check for character adv.
jrz ?in65 ; loop if NOT
lda key ; get the key code
push psw ; save on stack
xra a ; clear key
sta key
pop psw ; recover current key
ret
page
;==========================================================
; CHARACTER DEVICE INPUT STATUS
;==========================================================
;
;
;
dseg
?ins65: ; character input status
lda key ; is there already a key
ora a
jrnz ret$true ; yes, return true
mvi a,'I' ; no, test if any typed
call send$a
call get ; get key
ora a ; =0 if none
rz ; return character not advaliable
sta key ; was one, save in key
?outs65:
ret$true:
ori 0ffh
ret
key: db 0
page
;==========================================================
; CHARACTER DEVICE OUTPUT
;==========================================================
; the charactor to be output is in the C register
;
;
;
dseg
?out65: ; character output
mov a,c
push psw
mvi a,'O'
call send$a
pop psw
call send$a
; jmp get
; fall thru to GET
;==========================================================
; EXTERNAL DEVICE LOW LEVEL DRIVERS
;==========================================================
;
;
;
dseg
get:
call in$stat
jrz get
dcx b ; point to data reg (RxD)
inp a
mov c,a
ret
;
;
;
send$c:
mov a,c
send$a:
push psw ; save the character to be output
send$loop:
call out$stat
jrz send$loop
pop psw
dcx b : point to data register (TxD)
outp a
ret
;
;
;
in$stat:
lhld usart$adr
mov b,h
mov c,l
inx b ; point to status register
inp a
ani rxrdy
ret
;
;
;
out$stat:
lhld usart$adr
mov b,h
mov c,l
inx b ; point to status register
inp a
ani txrdy
ret
else
;==========================================================
; CHARACTOR INITILIZATION ROUTINES
;==========================================================
;
;
;
dseg
;
; set com rate to value in ?int$bd
; (may need to change rate if not supported)
?int65:
init$ext:
if use$6551
;
; must gate 6551 to user port
; this is done by init'ing the out data to an input
; and then setting DTR
;
lxi b,CIA2+data$dir$a
inp a
ori 100b ; make TxD bit (2) an input
outp a
endif
lhld usart$adr
mov b,h
mov c,l
inx b ; point to status reg
outp a ; software reset (wr to stat reg)
inx b ; point to Command register
mvi a,cmd$init ; set DTR active
outp a
inx b ; point to Control register
lda ?int$bd ; get 6551 baud rate
ori 10h ; use baud rate generator
outp a ; 1 stop (7=0), 8 bits (65=0)
ret
page
;==========================================================
; CHARACTOR INPUT ROUTINES
;==========================================================
;
;
;
dseg
?in65: ; character input
call ?ins65
jrz ?in65
dcx b ; point to data reg
inp a
ret
;==========================================================
; CHARACTER DEVICE INPUT STATUS
;==========================================================
;
;
;
dseg
?ins65: ; character input status
lhld usart$adr
mov b,h
mov c,l
inx b ; point to status register
inp a
ani rxrdy
rz
ori -1
ret
;==========================================================
; CHARACTER DEVICE OUTPUT
;==========================================================
; the charactor to be output is in the C register
;
;
;
dseg
?out65: ; character output
mov a,c
push psw
call ?outs65
jrz ?out65
pop psw
dcx b ; point to data register
outp a
ret
;==========================================================
; CHARACTER DEVICE OUTPUT STATUS
;==========================================================
;
;
;
dseg
?outs65: ; character input status
lhld usart$adr
mov b,h
mov c,l
inx b ; point to status register
inp a
ani txrdy
rz
ori -1
ret
endif
end