cpm/bin/BIOS.ASM
2020-09-19 22:18:31 +02:00

505 lines
12 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; MDS-800 I/O Drivers for CP/M 2.2
; (four drive single density version)
;
; Version 2.2 February, 1980
;
vers equ 22 ;version 2.2
;
; Copyright (c) 1980
; Digital Research
; Box 579, Pacific Grove
; California, 93950
;
;
true equ 0ffffh ;value of "true"
false equ not true ;"false"
test equ false ;true if test bios
;
if test
bias equ 03400h ;base of CCP in test system
endif
if not test
bias equ 0000h ;generate relocatable cp/m system
endif
;
patch equ 1600h
;
org patch
cpmb equ $-patch ;base of cpm console processor
bdos equ 806h+cpmb ;basic dos (resident portion)
cpml equ $-cpmb ;length (in bytes) of cpm system
nsects equ cpml/128 ;number of sectors to load
offset equ 2 ;number of disk tracks used by cp/m
cdisk equ 0004h ;address of last logged disk on warm start
buff equ 0080h ;default buffer address
retry equ 10 ;max retries on disk i/o before error
;
; perform following functions
; boot cold start
; wboot warm start (save i/o byte)
; (boot and wboot are the same for mds)
; const console status
; reg-a = 00 if no character ready
; reg-a = ff if character ready
; conin console character in (result in reg-a)
; conout console character out (char in reg-c)
; list list out (char in reg-c)
; punch punch out (char in reg-c)
; reader paper tape reader in (result to reg-a)
; home move to track 00
;
; (the following calls set-up the io parameter block for the
; mds, which is used to perform subsequent reads and writes)
; seldsk select disk given by reg-c (0,1,2...)
; settrk set track address (0,...76) for subsequent read/write
; setsec set sector address (1,...,26) for subsequent read/write
; setdma set subsequent dma address (initially 80h)
;
; (read and write assume previous calls to set up the io parameters)
; read read track/sector to preset dma address
; write write track/sector from preset dma address
;
; jump vector for indiviual routines
jmp boot
wboote: jmp wboot
jmp const
jmp conin
jmp conout
jmp list
jmp punch
jmp reader
jmp home
jmp seldsk
jmp settrk
jmp setsec
jmp setdma
jmp read
jmp write
jmp listst ;list status
jmp sectran
;
maclib diskdef ;load the disk definition library
disks 4 ;four disks
diskdef 0,1,26,6,1024,243,64,64,offset
diskdef 1,0
diskdef 2,0
diskdef 3,0
; endef occurs at end of assembly
;
; end of controller - independent code, the remaining subroutines
; are tailored to the particular operating environment, and must
; be altered for any system which differs from the intel mds.
;
; the following code assumes the mds monitor exists at 0f800h
; and uses the i/o subroutines within the monitor
;
; we also assume the mds system has four disk drives
revrt equ 0fdh ;interrupt revert port
intc equ 0fch ;interrupt mask port
icon equ 0f3h ;interrupt control port
inte equ 0111$1110b ;enable rst 0(warm boot), rst 7 (monitor)
;
; mds monitor equates
mon80 equ 0f800h ;mds monitor
rmon80 equ 0ff0fh ;restart mon80 (boot error)
ci equ 0f803h ;console character to reg-a
ri equ 0f806h ;reader in to reg-a
co equ 0f809h ;console char from c to console out
po equ 0f80ch ;punch char from c to punch device
lo equ 0f80fh ;list from c to list device
csts equ 0f812h ;console status 00/ff to register a
;
; disk ports and commands
base equ 78h ;base of disk command io ports
dstat equ base ;disk status (input)
rtype equ base+1 ;result type (input)
rbyte equ base+3 ;result byte (input)
;
ilow equ base+1 ;iopb low address (output)
ihigh equ base+2 ;iopb high address (output)
;
readf equ 4h ;read function
writf equ 6h ;write function
recal equ 3h ;recalibrate drive
iordy equ 4h ;i/o finished mask
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
;
signon: ;signon message: xxk cp/m vers y.y
db cr,lf,lf
if test
db '32' ;32k example bios
endif
if not test
db '00' ;memory size filled by relocator
endif
db 'k CP/M vers '
db vers/10+'0','.',vers mod 10+'0'
db cr,lf,0
;
boot: ;print signon message and go to ccp
; (note: mds boot initialized iobyte at 0003h)
lxi sp,buff+80h
lxi h,signon
call prmsg ;print message
xra a ;clear accumulator
sta cdisk ;set initially to disk a
jmp gocpm ;go to cp/m
;
;
wboot:; loader on track 0, sector 1, which will be skipped for warm
; read cp/m from disk - assuming there is a 128 byte cold start
; start.
;
lxi sp,buff ;using dma - thus 80 thru ff available for stack
;
mvi c,retry ;max retries
push b
wboot0: ;enter here on error retries
lxi b,cpmb ;set dma address to start of disk system
call setdma
mvi c,0 ;boot from drive 0
call seldsk
mvi c,0
call settrk ;start with track 0
mvi c,2 ;start reading sector 2
call setsec
;
; read sectors, count nsects to zero
pop b ;10-error count
mvi b,nsects
rdsec: ;read next sector
push b ;save sector count
call read
jnz booterr ;retry if errors occur
lhld iod ;increment dma address
lxi d,128 ;sector size
dad d ;incremented dma address in hl
mov b,h
mov c,l ;ready for call to set dma
call setdma
lda ios ;sector number just read
cpi 26 ;read last sector?
jc rd1
; must be sector 26, zero and go to next track
lda iot ;get track to register a
inr a
mov c,a ;ready for call
call settrk
xra a ;clear sector number
rd1: inr a ;to next sector
mov c,a ;ready for call
call setsec
pop b ;recall sector count
dcr b ;done?
jnz rdsec
;
; done with the load, reset default buffer address
gocpm: ;(enter here from cold start boot)
; enable rst0 and rst7
di
mvi a,12h ;initialize command
out revrt
xra a
out intc ;cleared
mvi a,inte ;rst0 and rst7 bits on
out intc
xra a
out icon ;interrupt control
;
; set default buffer address to 80h
lxi b,buff
call setdma
;
; reset monitor entry points
mvi a,jmp
sta 0
lxi h,wboote
shld 1 ;jmp wboot at location 00
sta 5
lxi h,bdos
shld 6 ;jmp bdos at location 5
if not test
sta 7*8 ;jmp to mon80 (may have been changed by ddt)
lxi h,mon80
shld 7*8+1
endif
; leave iobyte set
; previously selected disk was b, send parameter to cpm
lda cdisk ;last logged disk number
mov c,a ;send to ccp to log it in
ei
jmp cpmb
;
; error condition occurred, print message and retry
booterr:
pop b ;recall counts
dcr c
jz booter0
; try again
push b
jmp wboot0
;
booter0:
; otherwise too many retries
lxi h,bootmsg
call prmsg
jmp rmon80 ;mds hardware monitor
;
bootmsg:
db '?boot',0
;
;
const: ;console status to reg-a
; (exactly the same as mds call)
jmp csts
;
conin: ;console character to reg-a
call ci
ani 7fh ;remove parity bit
ret
;
conout: ;console character from c to console out
jmp co
;
list: ;list device out
; (exactly the same as mds call)
jmp lo
;
listst:
;return list status
xra a
ret ;always not ready
;
punch: ;punch device out
; (exactly the same as mds call)
jmp po
;
reader: ;reader character in to reg-a
; (exactly the same as mds call)
jmp ri
;
home: ;move to home position
; treat as track 00 seek
mvi c,0
jmp settrk
;
seldsk: ;select disk given by register c
lxi h,0000h ;return 0000 if error
mov a,c
cpi ndisks ;too large?
rnc ;leave HL = 0000
;
ani 10b ;00 00 for drive 0,1 and 10 10 for drive 2,3
sta dbank ;to select drive bank
mov a,c ;00, 01, 10, 11
ani 1b ;mds has 0,1 at 78, 2,3 at 88
ora a ;result 00?
jz setdrive
mvi a,00110000b ;selects drive 1 in bank
setdrive:
mov b,a ;save the function
lxi h,iof ;io function
mov a,m
ani 11001111b ;mask out disk number
ora b ;mask in new disk number
mov m,a ;save it in iopb
mov l,c
mvi h,0 ;HL=disk number
dad h ;*2
dad h ;*4
dad h ;*8
dad h ;*16
lxi d,dpbase
dad d ;HL=disk header table address
ret
;
;
settrk: ;set track address given by c
lxi h,iot
mov m,c
ret
;
setsec: ;set sector number given by c
lxi h,ios
mov m,c
ret
sectran:
;translate sector bc using table at de
mvi b,0 ;double precision sector number in BC
xchg ;translate table address to HL
dad b ;translate(sector) address
mov a,m ;translated sector number to A
sta ios
mov l,a ;return sector number in L
ret
;
setdma: ;set dma address given by regs b,c
mov l,c
mov h,b
shld iod
ret
;
read: ;read next disk record (assuming disk/trk/sec/dma set)
mvi c,readf ;set to read function
call setfunc
call waitio ;perform read function
ret ;may have error set in reg-a
;
;
write: ;disk write function
mvi c,writf
call setfunc ;set to write function
call waitio
ret ;may have error set
;
;
; utility subroutines
prmsg: ;print message at h,l to 0
mov a,m
ora a ;zero?
rz
; more to print
push h
mov c,a
call conout
pop h
inx h
jmp prmsg
;
setfunc:
; set function for next i/o (command in reg-c)
lxi h,iof ;io function address
mov a,m ;get it to accumulator for masking
ani 11111000b ;remove previous command
ora c ;set to new command
mov m,a ;replaced in iopb
; the mds-800 controller requires disk bank bit in sector byte
; mask the bit from the current i/o function
ani 00100000b ;mask the disk select bit
lxi h,ios ;address the sector select byte
ora m ;select proper disk bank
mov m,a ;set disk select bit on/off
ret
;
waitio:
mvi c,retry ;max retries before perm error
rewait:
; start the i/o function and wait for completion
call intype ;in rtype
call inbyte ;clears the controller
;
lda dbank ;set bank flags
ora a ;zero if drive 0,1 and nz if 2,3
mvi a,iopb and 0ffh ;low address for iopb
mvi b,iopb shr 8 ;high address for iopb
jnz iodr1 ;drive bank 1?
out ilow ;low address to controller
mov a,b
out ihigh ;high address
jmp wait0 ;to wait for complete
;
iodr1: ;drive bank 1
out ilow+10h ;88 for drive bank 10
mov a,b
out ihigh+10h
;
wait0: call instat ;wait for completion
ani iordy ;ready?
jz wait0
;
; check io completion ok
call intype ;must be io complete (00) unlinked
; 00 unlinked i/o complete, 01 linked i/o complete (not used)
; 10 disk status changed 11 (not used)
cpi 10b ;ready status change?
jz wready
;
; must be 00 in the accumulator
ora a
jnz werror ;some other condition, retry
;
; check i/o error bits
call inbyte
ral
jc wready ;unit not ready
rar
ani 11111110b ;any other errors? (deleted data ok)
jnz werror
;
; read or write is ok, accumulator contains zero
ret
;
wready: ;not ready, treat as error for now
call inbyte ;clear result byte
jmp trycount
;
werror: ;return hardware malfunction (crc, track, seek, etc.)
; the mds controller has returned a bit in each position
; of the accumulator, corresponding to the conditions:
; 0 - deleted data (accepted as ok above)
; 1 - crc error
; 2 - seek error
; 3 - address error (hardware malfunction)
; 4 - data over/under flow (hardware malfunction)
; 5 - write protect (treated as not ready)
; 6 - write error (hardware malfunction)
; 7 - not ready
; (accumulator bits are numbered 7 6 5 4 3 2 1 0)
;
; it may be useful to filter out the various conditions,
; but we will get a permanent error message if it is not
; recoverable. in any case, the not ready condition is
; treated as a separate condition for later improvement
trycount:
; register c contains retry count, decrement 'til zero
dcr c
jnz rewait ;for another try
;
; cannot recover from error
mvi a,1 ;error code
ret
;
; intype, inbyte, instat read drive bank 00 or 10
intype: lda dbank
ora a
jnz intyp1 ;skip to bank 10
in rtype
ret
intyp1: in rtype+10h ;78 for 0,1 88 for 2,3
ret
;
inbyte: lda dbank
ora a
jnz inbyt1
in rbyte
ret
inbyt1: in rbyte+10h
ret
;
instat: lda dbank
ora a
jnz insta1
in dstat
ret
insta1: in dstat+10h
ret
;
;
;
; data areas (must be in ram)
dbank: db 0 ;disk bank 00 if drive 0,1
; 10 if drive 2,3
iopb: ;io parameter block
db 80h ;normal i/o operation
iof: db readf ;io function, initial read
ion: db 1 ;number of sectors to read
iot: db offset ;track number
ios: db 1 ;sector number
iod: dw buff ;io address
;
;
; define ram areas for bdos operation
endef
end