;	MP/M 2.0 Loader BIOS
;	(modified CP/M 2.2 BIOS)


;	MDS I/O drivers for CP/M 2.2
;	(single drive, single density)
;		     -or-
;	(single drive, double density)

;	Version 2.0   --    Sept 81

vers	equ	20	;version 2.0

;	Copyright (C) 1980, 1981
;	Digital Research
;	Box 579, Pacific Grove
;	California, 93950

false	equ	0
true	equ	not false

asm	equ	true
mac	equ	not asm

sgl	equ	true
dbl	equ	not sgl

	if	mac
	maclib	diskdef
numdsks equ	1	;number of drives available
	endif

ram$top	equ	1d00h	 	; top address+1
bios	equ	ram$top-0600h	; basic input/output system
bdos	equ	bios-0e00h	; base of the bdos

	org	bios


buff	equ	0080h	;default buffer address

retry	equ	10	;max retries on disk i/o before error

;	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	list$st		; list status poll
	jmp	sect$tran	; sector translation


;	we also assume the MDS system has four disk drives

numdisks equ	1	;number of drives available
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

rmon80	equ	0ff0fh	;restart mon80 (boot error)

;	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

boot:

wboot:
gocpm:
	ret

crtin:			; crt: input
	in 0f7h ! ani 2 ! jz crtin
	in 0f6h ! ani 7fh
	ret
crtout:			; crt: output
	in 0f7h ! ani 1 ! jz crtout
	mov a,c ! out 0f6h
	ret
crtst:			; crt: status
	in 0f7h ! ani 2 ! rz
	ori 0ffh 
	ret
ttyin:			; tty: input
	in 0f5h ! ani 2 ! jz ttyin
	in 0f4h ! ani 7fh
	ret
ttyout:			; tty: output
	in 0f5h ! ani 1 ! jz ttyout
	mov a,c ! out 0f4h
	ret
;ttyst:
;	in 0f5h ! ani 2 ! rz
;	ori -1
;	ret

lptout:			; lpt: output
	in 0fbh ! ani 1 ! jz lptout
 	mov a,c ! cma ! out 0fah
	ret

lpt$st:
	in 0fbh ! ani 1 ! rz
	ori 0ffh
	ret

conin	equ	crtin
const	equ	crtst
conout	equ	crtout
reader	equ	ttyin
punch	equ	ttyout
list	equ	lptout
listst	equ	lptst



seldsk:	;select disk given by register c
	lxi h, 0 ! mov a,c ! cpi num$disks ! rnc  ; first, insure good select
	ani 2 ! sta dbank	; then save it
	lxi h,sel$table ! mvi b,0 ! dad b ! mov a,m ! sta iof
	mov h,b ! mov l,c
	dad h ! dad h ! dad h ! dad h	; times 16
	lxi d,dpbase ! dad d
	ret

home:	;move to home position
;	treat as track 00 seek
	mvi	c,0
;
settrk:	;set track address given by c
	lxi	h,iot
	mov	m,c
	ret
;
setsec:	;set sector number given by c
	mov	a,c	;sector number to accum
	sta	ios	;store sector number to iopb
	ret
;
setdma:	;set dma address given by regs b,c
	mov	l,c
	mov	h,b
	shld	iod
	ret

sect$tran:		; translate the sector # in <c> if needed
	mov h,b ! mov l,c ! inx h  ; in case of no translation
	mov a, d ! ora e ! rz	
	xchg ! dad b	; point to physical sector
	mov l,m ! mvi h,0
	ret


read:	;read next disk record (assuming disk/trk/sec/dma set)
	mvi	c,readf	;set to read function
	jmp	setfunc
;
write:	;disk write function
	mvi	c,writf
;
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	1111$1000b	;remove previous command
	ora	c	;set to new command
	mov	m,a	;replaced in iopb
;	single density drive 1 requires bit 5 on in sector #
;	mask the bit from the current i/o function
	ani	0010$0000b	;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
;
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)

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


;	utility subroutines

prmsg:	;print message at h,l to 0
	mov a,m ! ora a ! rz
	push h ! mov c,a ! call conout ! pop h
	inx h ! jmp prmsg


;	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	2	;track number
ios:	db	1	;sector number
iod:	dw	buff	;io address
;
;

sel$table:
	if	sgl
	db	00h, 30h, 00h, 30h	; drive select bits
	endif
	if	dbl
	db	00h, 10h, 00h, 30h	; drive select bits
	endif

	if	mac and sgl
	disks	numdisks		; generate drive tables
	diskdef	0,1,26,6,1024,243,64,64,2
	endef
	endif

	if	mac and dbl
	disks	numdisks		; generate drive tables
	diskdef 0,1,52,,2048,243,128,128,2,0
	endef
	endif

	if	asm
dpbase	equ	$		;base of disk param blks
dpe0:	dw	xlt0,0000h	;translate table
	dw	0000h,0000h	;scratch area
	dw	dirbuf,dpb0	;dir buff, parm block
	dw	csv0,alv0	;check, alloc vectors
dpb0	equ	$		;disk param block
	endif

	if	asm and sgl
	dw	26		;sec per track
	db	3		;block shift
	db	7		;block mask
	db	0		;extnt mask
	dw	242		;disk size-1
	dw	63		;directory max
	db	192		;alloc0
	db	0		;alloc1
	dw	16		;check size
	dw	2		;offset
xlt0	equ	$		;translate table
	db	1
	db	7
	db	13
	db	19
	db	25
	db	5
	db	11
	db	17
	db	23
	db	3
	db	9
	db	15
	db	21
	db	2
	db	8
	db	14
	db	20
	db	26
	db	6
	db	12
	db	18
	db	24
	db	4
	db	10
	db	16
	db	22
	endif

	if	asm and dbl
xlt0	equ	0
	endif

	if	asm
begdat	equ	$
dirbuf:	ds	128		;directory access buffer
alv0:	ds	31
csv0:	ds	16
	endif

	if	asm and dbl
	ds	16
	endif

	if	asm
enddat	equ	$
datsiz	equ	$-begdat
	endif

	end

