
;CPM 2.2 BIOS 
;This bios does not detect logins of different types of disks
; HOWEVER, this bios will allow you to write new values into 
; DPBs and XLTs to define varieous types of disks
;
;It supports 16 bit values for track and sector
;  but only supports 8 bit sector translations
;
;each drive has its own DPB,Allocation tables, 
;directory check vectors and translate tables
;
;A:and B:(at cold boot, set for PC1440 disks)
;   Allocation = 91 bytes
;   Check=64 bytes
;   XLT=0 (no area reserved)
;
;B: and C:(at cold boot, set to IBM3740--but with lots of extra room)
;   Allocation = 256 bytes (depends on block size, but plenty for many disk 
;                           definitions)
;   Check=256 bytes (enough for 1024 Directory entries)
;   XLT=128 bytes (enough for disks with up to 128 SPT)
;   	XLTs at f500 and f580 for 62 k system
; 
; use the CNFGDISK.COM program to change drive C: and D: parameters
;
;1K at f600-f9ff (62k system) is unused(reserved for XBIOS) and can be used if needed
; 

true	equ	-1
false	equ	not true

;Banked22	equ	false
Banked22	equ	true
;AS8080		equ	false
AS8080		equ	true

	if 	AS8080
		z80
	else
		maclib	z80
	endif

IBM$C$D	equ	false

nk$sys	equ	62		;system size in  kBytes
td	equ	nk$sys/10	;decimal tens digit
od	equ	nk$sys MOD 10	;decimal ones digit
td$asc	equ	td+30h		;ascci tens digit
od$asc	equ	od+30h		;ascii ones digit
k$byte	equ	1024		;bytes in a kilobyte
cpm$sz	equ	nk$sys*k$byte	;top system addres
v$20k	equ	20*k$byte	;twenty kByte 
cpm$bs	equ	cpm$sz-v$20k	;cpm bias value
ccp	equ	cpm$bs+3400h	;addres of ccp
bdos	equ	cpm$bs+3c00h	;addres of bdos
bios	equ	cpm$bs+4a00h	;addres of bios
;bios$r	equ	1000h-bios	;DDT offset load?
tpa	equ	100h		;addres of TPA
initIOB	equ	0ffh		;initial iobyte value

io$byte	equ	3		;address of iobyte
c$disk	equ	4		;address of current logged disk

;un-initialized data definition

ui$data	equ	0fA00h		;6 256 blocks 

df$drv	equ	0		;default drive
sec$sz	equ	80h		;sector size

n$drvs	equ	4		;number of drives(1-4)

dsk$cmd 	equ 	0D0h 
dsk$sts 	equ 	0D0h 
dsk$drv		equ	0D1h ;drv
dsk$trkL	equ	0D2h ;trkLow
dsk$trkH	equ	0D3h ;trkHigh
dsk$secL	equ	0D4h ;secLow
dsk$secH	equ	0D5h ;secHigh
dsk$dmaL	equ	0D6h ;dmaLow
dsk$dmaH	equ	0D7h ;dmaHigh
dsk$sptL	equ	0D8h ;sptLow
dsk$sptH	equ	0D9h ;sptHigh
dsk$dmaB	equ	0dah ;Disk DMA Bank
dsk$order	equ	0dbh ;track order

cmd$read	equ	1
cmd$write	equ	2
cmd$log		equ	4
cmd$fmt		equ	8

	org	bios

;bios jump vector table

	jmp	init	;cold start
	jmp	warm	;warm start - reload ccp + bdos
	jmp	cns$ck	;get console status
	jmp	cns$in	;console input
outCH:	jmp	cns$ot	;console output
	jmp	list	;printer output
	jmp	punch	;punch output
	jmp	reader	;reader input
	jmp	home	;home selected drive
	jmp	seldsk	;select drive
	jmp	settrk	;set track
	jmp	setsec	;set sector
	jmp	setdma	;set tranfer address
	jmp	diskrd	;read disk
	jmp	diskwr	;write disk
	jmp	listst	;getr printer status
	jmp	sectrn	;translate sector
	jmp	dsk$ok	; claim JaddeDD format worked (plus make old versions of cnfgdisk fail)
; because magic is moved to next three bytes... 
	db	076h,076h,076h	;flag for Disk Config Program

;bios variable storage

bt$cmd	db	0	;dcm command
bt$drv	db	0	;drive number
bt$trk	dw	0	;track number
bt$sec	dw	0	;sector number
bt$sp0	db	0	;spare
bt$sp1	db	0	;spare
bt$mod	db	0	;mode controls
bt$sts	db	0	;command status

bt$lad	dw	0	;load address
bt$lng	dw	0	;load length
bt$dma	dw	0	;system tranfer address

dt$ptr	dw	0	;drive table pointer
log$rq	db	0	;log on request

;init stuff is overlayed by directory buffer

dir$bf	equ	$

;get system size in ascii

init	lxi	sp,0080h	;set initial stack

c$logo	lxi	h,msg$so	;sign on message
	call	msg$ot		;out message
	lhld	bios+4		;get warm address
	shld	bios+1		;make cold point to warm

	if 	Banked22
	 mvi	a,1		;bank	1
	 out	0c0h		;emu bank select
	endif

	xra	a		;clear accumulator
	sta	io$byte		;store at iobyte
	sta	c$disk		;current logged disk =0

	if 	Banked22
	 xra	a		;bank	0
	 out	0c0h		;emu bank select

	 mvi	e,0	;1	; log on request
	 mvi	c,0		;drive 0
	 call	seldsk		;select drive
	 lxi	b,8000h	;cpm ccp address in bank 0
	 call	setdma		;set dma
	 lxi	b,29		;first ccp sector(128)
	 call	setsec		;set sector
	 lxi	b,0		;ccp/bdos track
	 call	settrk		;set track
w$read	 call	diskrd		;read one sector
	 ana	a		;set flags(ccr)
	 jrnz	w$eror		;exit if error
	 lda	bt$sec		;get sector number
	 cpi	72		;last SECTOR(128)
	 jz	warm		;go init page zero
	 inr	a		;next sector
	 sta	bt$sec		;store next sector
	 lxi	d,sec$sz	;sector size
	 lhld	bt$dma		;inc buffer pointer to next sec
 	 dad	d		;new buffer address 
	 shld	bt$dma		;store new buffer address
	 mvi	c,2ah		;
	 call	outCH		;splash progress bar
	 jr	w$read		;again

w$eror lxi	h,msg$le	;display error msg
	 call	msg$ot		;and
	 hlt			;halt

	else

	 jmp	warm		;do warm boot

	endif

msg$so	db	cr,lf
sys$td	db	td$asc		;tens digit
sys$od	db	od$asc		;ones digit
		db	'K CPM 2.2-D V2'
	if 	Banked22
		db	'-Banked'
	endif
	db	cr,lf+80h	;sign bit set on last byte

eoinit	equ	$	;end of init stuff

;fill out directory buffer dir$buf
	if eoinit lt (dir$bf+80h)
	org	dir$bf+80h
	endif

;disk executive

dsk$ex

;	New Disk Interface

	mvi	a,010h	;select DMA
	out	0cah	;disk reg select
	lda	bt$dma
	out	0c8h	;dsk$dmaL
	lda	bt$dma+1	
	out	0c9h	;dsk$dmaH

	mvi	a,018h	;select Drive
	out	0cah	;disk reg select
	lda	bt$drv
	out	0c8h	;dsk$drv

	mvi	a,022h	;select track
	out	0cah	;disk reg select
	lda	bt$trk
	out	0c8h	;dsk$trkL
	lda	bt$trk+1	
	out	0c9h	;dsk$trkH

	mvi	a,024h	;select sector
	out	0cah	;disk reg select
	lda	bt$sec
	out	0c8h	;dsk$secL
	lda	bt$sec+1	
	out	0c9h	;dsk$secH

	mvi	a,000h	;select Command
	out	0cah	;disk reg select
	lda	bt$cmd
	out	0c8h	;dsk$cmd

	mvi	a,08h	;select status
	out	0cah	;disk reg select
	in	0c8h	;dsk$sts

	ana	a		;set ccr
	ret

;read sector

diskrd:
	mvi	a,cmd$read
	sta	bt$cmd
	call	dsk$ex		;perform operation
	jrz	dsk$ok		;normal exit
	jr	dsk$er		;exit error

;write sector

diskwr:	
	mvi	a,cmd$write
	sta	bt$cmd
	call	dsk$ex		;perform operation
	jrz	dsk$ok		;normal exit if write ok
	jr	dsk$er		;exit error

;disk read write format exits and errors

dsk$ok:	
	xra	a		;clear a to indicate OK
	ret

dsk$er:	
	mvi	a,0FFh		;set a to indicate ERROR
	ret

seldsk	lxi	h,0		;hl = zero if error
	mov	a,c		;put drive number in a
	sta	bt$drv		;store drive number
	cpi	n$drvs		;check if legal drive number
	rnc			;ret if illegal

	mov	a,e		;chk if need log on
	sta	log$rq		;save log on req in log$rq
	
retdsk	lda	bt$drv		;get drv number
	mov	l,a		;l=drive number
	mvi	h,0		;clear h
	dad	h		;*2
	dad	h		;*4
	dad	h		;*8
	dad	h		;*16
	lxi	d,d0$dph	;first dph
	dad	d		;hl=dph of drv number in c
	shld	dt$ptr		;store drive table pointer
	jr	dsk$ok

;get drv par block address

dpb$ad	lhld	dt$ptr		;ptr to dph table
	lxi	d,10		;
	dad	d		;d points to dpb in dph
	mov	e,m		;get dpb from dph at offset 10
	inx	h		;
	mov	d,m		;
	ret

;home drive

home	mvi	c,0		;set track to 0 fall into settrk
	mov	b,c

;set track

settrk	
	sbcd	bt$trk		;store track number 16 bits
	ret

;set sector

setsec	
	sbcd	bt$sec		;store sector number High
	ret

;set dma

setdma	
	sbcd	bt$dma	 	;just save in bt$dma
	ret

;sector translation

sectrn	mov	a,d		;testing tbl addr
	ora	e		;chk if 0
	jrz	notran		;no xlation
	xchg			;hl=xlat tbl
	dad	b		;hl + sec offset
	mov	l,m		;
	mvi	h,0		;assumed 8 bit sector numbers
	ret	
notran	lxi	h,1		;add one to sector number and ret
	dad	b		
	ret	

;define console io ports

cni$sp	equ	7dh
cni$sb	equ	02h
cni$si	equ	00h
cni$dp	equ	7ch

cno$sp	equ	7dh
cno$sb	equ	01h
cno$si	equ	00h
cno$dp	equ	7ch

io$rdy	equ	0FFh	;ready
asc$msk	equ	7Fh	;ascii mask

lf	equ	0ah
cr	equ	0dh
cntl$z	equ	1Ah

;console input status


cns$ck	in	cni$sp		;in status
	xri	cni$si		;adjust polarity
	ani	cni$sb		;mask status bit
	rz			;return zero if not ready
	mvi	a,io$rdy	;set ready
	ret			;return

;console input

cns$in	call	cns$ck		;check status
	jrz	cns$in		;repeat untill ready
	in	cni$dp		;in character
	ani	asc$msk		;mask to 7 bit ascii
	ret			;return

;console output

cns$ot	in	cno$sp		;in status
	xri	cno$si		;adjust polarity
	ani	cno$sb		;mask status bit
	jrz	cns$ot		;repeat untill ready
	mov	a,c		;get character in a
	ani	asc$msk		;mask to 7 bit ascii
	out	cno$dp		;out character
	ret			;return

;reader and punch

reader	mvi	a,cntl$z	;return eof
	ret			;return

punch	ret			;throw away

;printer

lst$dp	equ	7eH		;list data port
lst$st	equ	7fH		;list status port
lst$ctl	equ	lst$st		;control port
lst$msk	equ	00000001B	;status mask (ORPLY)
ctl$msk	equ	00000001b	;control mask (OSTB)
mem$msk	equ	00000010b	;sbc mem mask 10=out 00=in

listst	in	lst$st		;
	ani	lst$msk		;
	rz			;not ready
	mvi	a,0ffh		;ready
	ret
	
list	call	listst		;get status
	jrz	list		;wait for ready
	mov	a,c		;get char from c
	out	lst$dp		;out char to data port
	mvi	a,ctl$msk		;strobe data
	out	lst$ctl		;strobe
	ret			;return

;display string

msg$ot	push	psw		;save ccr and a
loop3	mov	c,m		;get char fron where hl points
	call	outCH		;output char
	mov	a,m		;get char again to test sign
	inx	hl		;inc to next char
	ani	80h		;test sign bit
	jrz	loop3		;repeat until sign bit set
	pop	psw		;restore ccr and a
	ret			;;return

;block	mov	a,m		;
;	stax	d		;
;	inx	h		;
;	inx	d		;
;	dcx	b		;
;	mov	a,b		;
;	ora	c		;
;	jnz	block		;
;	ret			;

;warm boot loads ccp + bdos sets up page zero

warm	lxi	sp,0080h	;set up stack in def buffer
	
	if	Banked22

	 mvi	a,0		;bank	0
	 out	0c0h		;expandoram ii bank select
	mvi	a,0c3h		;jmp xxxx = (c3 xx xx)
	sta	0		;
	lxi	h,bios+03	;jmp bios+3(warm)
	shld	1		;init warm vector in bank 0 so reset works
	 lxi	hl,8000h	;loc of ccp and bdos in bnk0
	 lxi	de,ccp		;loc of ccp and bdos in bnk1
	 lxi	bc,44*128	;size of ccp and bdos
	 ldir
;	 call 	block
	 mvi	a,1		;bank	1
	 out	0c0h		;expandoram ii bank select

	else

	 mvi	e,0	;1	;log on request
	 mvi	c,0		;drive 0
	 call	seldsk		;select drive
	 lxi	b,ccp		;cpm ccp address
	 call	setdma		;set dma
	 lxi	b,29		;first ccp sector(128)
	 call	setsec		;set sector
	 lxi	b,0		;ccp/bdos track
	 call	settrk		;set track
	
;read ccp and bdos
	 mvi	c,0dh		;
	 call	outCH		;cr
	 mvi	c,0ah		;
	 call	outCH		;lf

w$read	 call	diskrd		;read one sector
	 ana	a		;set flags(ccr)
	 jrnz	w$eror		;exit if error
	 lda	bt$sec		;get sector number
	 cpi	72		;last SECTOR(128)
	 jrz	w$zrpg		;go init page zero
	 inr	a		;next sector
	 sta	bt$sec		;store next sector
	 lxi	d,sec$sz	;sector size
	 lhld	bt$dma		;inc buffer pointer to next sec
	 dad	d		;new buffer address 
	 shld	bt$dma		;store new buffer address
	 mvi	c,2ah		;
	 call	outCH		;splash progress bar
	 jr	w$read		;again 

w$eror	 lxi	h,msg$le	;display error msg
	 call	msg$ot		;and
	 hlt			;halt
	endif

;init page zero

w$zrpg	mvi	a,0c3h		;jmp xxxx = (c3 xx xx)
	sta	0		;
	lxi	h,bios+03	;jmp bios+3(warm)
	shld	1
	sta	5		;jmp instruction
	lxi	h,bdos+06	;jmp bdos (ccp+6)
	shld	6
	sta	38h		;rst 7
	lxi	h,0e003h	;jmp sdmon(e003)
	shld	39h

;last logged drive

	lda	c$disk		;last drive used
	mov	c,a		;ccp expects it in c
	
	lxi	h,0080h	;set default dma
	shld	bt$dma		;

;jump to ccp

	jmp	ccp		;go to cpm


;default drive parametr block for 3$5" pc1440

d0$dpb:	dw	72		;spt
	db	4		;bsh
	db	15		;blm
	db	0		;exm
	dw	710		;dsm
	dw	255		;drm
	db	0f0h		;al0
	db	0		;al1
	dw	64		;cks
	dw	2		;off
	db	0		; PSH
	db	0		; PHM


d1$dpb:	dw	72		;spt
	db	4		;bsh
	db	15		;blm
	db	0		;exm
	dw	710		;dsm
	dw	255		;drm
	db	0f0h		;al0
	db	0		;al1
	dw	64		;cks
	dw	2		;off
	db	0		; PSH
	db	0		; PHM
	
	if	IBM$C$D

;default drive parametr block for 8" IBM3740

d2$dpb:	dw	26		;spt
	db	3		;bsh
	db	7		;blm
	db	0		;exm
	dw	242		;dsm
	dw	63		;drm
	db	0c0h		;al0
	db	0		;al1
	dw	16		;cks
	dw	2		;off
	db	0		; PSH
	db	0		; PHM

d3$dpb:	dw	26		;spt
	db	3		;bsh
	db	7		;blm
	db	0		;exm
	dw	242		;dsm
	dw	63		;drm
	db	0c0h		;al0
	db	0		;al1
	dw	16		;cks
	dw	2		;off
	db	0		; PSH
	db	0		; PHM

	else

;default drive parametr block for 3$5" pc1440

d2$dpb:	dw	72		;spt
	db	4		;bsh
	db	15		;blm
	db	0		;exm
	dw	710		;dsm
	dw	255		;drm
	db	0f0h		;al0
	db	0		;al1
	dw	64		;cks
	dw	2		;off
	db	0		; PSH
	db	0		; PHM

d3$dpb:	dw	72		;spt
	db	4		;bsh
	db	15		;blm
	db	0		;exm
	dw	710		;dsm
	dw	255		;drm
	db	0f0h		;al0
	db	0		;al1
	dw	64		;cks
	dw	2		;off
	db	0		; PSH
	db	0		; PHM

	endif

;messages

msg$le:	db	cr,lf,'LOAD ERRO'
		db	52h+80h

;drive parameter area

d0$dph:	dw	0		;xlat table
	dw	0		;scratch area
	dw	0		;scratch area
	dw	0		;scratch area
	dw	dir$bf		;directory buffer
	dw	d0$dpb		;drive parameter block
	dw	d0$chk		;chk for disk change area
	dw	d0$all		;drive allocation table

d1$dph:	dw	0
	dw	0
	dw	0
	dw	0
	dw	dir$bf
	dw	d1$dpb
	dw	d1$chk
	dw	d1$all

d2$dph:
	if IBM$C$D
	dw	d2$xlt
	else
	dw	0
	endif
	dw	0
	dw	0
	dw	0
	dw	dir$bf
	dw	d2$dpb
	dw	d2$chk
	dw	d2$all

d3$dph:
	if IBM$C$D
	dw	d3$xlt
	else
	dw	0
	endif
	dw	0
	dw	0
	dw	0
	dw	dir$bf
	dw	d3$dpb
	dw	d3$chk
	dw	d3$all

; eob must be less than bios + 0x300
eob:	equ	$


;Sector Translate Tables must be here....
	org	bios+0300h
d2$xlt:	db	01h,07h,0dh,13h,19h,05h
		db	0bh,11h,17h,03h,09h,0fh
		db	15h,02h,08h,0eh,14h,1ah
		db	06h,0ch,12h,18h,04h,0ah
		db	10h,16h
		org	d2$xlt+128

d3$xlt:	db	01h,07h,0dh,13h,19h,05h
		db	0bh,11h,17h,03h,09h,0fh
		db	15h,02h,08h,0eh,14h,1ah
		db	06h,0ch,12h,18h,04h,0ah
		db	10h,16h
		org	d3$xlt+128
	

;Un-initialized data area

	org	ui$data

; drive allocation area

all$sz 	set	91

d0$all	equ	$
d1$all	equ	d0$all+all$sz
d2$all	equ	d1$all+all$sz
all$sz 	set	256
d3$all	equ	d2$all+all$sz

;changed disk area

d0$chk	equ	d3$all+all$sz
chk$sz	set	64
d1$chk	equ	d0$chk+chk$sz
d2$chk	equ	d1$chk+chk$sz
chk$sz	set	256
d3$chk	equ	d2$chk+chk$sz

eoui	equ	d3$chk+chk$sz
