	title 'PCxxxx ibm3740 and HD4mb HD512mb disk handler with login feature'
;    CP/M-80 Version 3     --  Modular BIOS

;	Disk I/O Module for z80 Emulator 
; 	This module must be used with the modified BIOSKRNL that 
;		returns one based sector numbers.

	dseg

    ; Disk drive dispatching tables for linked BIOS

	public	fdpc0,fdpc1,fdpc2,fdpc3
	public 	fdsd0,fdsd1
	public	fdpc6,fdpc7
	public	hd4m0,hd4m1
	public	fdpc10,fdpc11,fdpc12,fdpc13,fdpc14,fdpc15

    ; Variables containing parameters passed by BDOS

	extrn	@adrv,@rdrv
	extrn	@dma,@trk,@sect
	extrn	@dbnk

    ; System Control Block variables

	extrn	@ermde		; BDOS error mode

    ; Utility routines in standard BIOS

	extrn	?wboot	; warm boot vector
	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


    ; Port Address Equates


	;disk command constants

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

    ; CP/M 3 Disk definition macros

	maclib cpm3

    ; Z80 macro library instruction definitions

	maclib z80

    ;macros for defining disk defintion data for the NDI

Set8	macro	?Register,?Value
	db	1,?Register,?Value
	endm

Set16	macro	?Register,?Value
	db	2,?Register
	dw	?Value
	endm

    ; common control characters

cr	equ 13
lf	equ 10
bell	equ 7

    ; Extended Disk Parameter Headers (XPDHs)

;These default to PC1440

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init0
	db	0,0		; relative drive zero
fdpc0	dph     0,dpbpc0	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init1
	db	1,0		; relative drive one
fdpc1	dph	0,dpbpc1	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init2
	db	2,0		; relative drive two
fdpc2	dph	0,dpbpc2	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init3
	db	3,0		; relative drive three
fdpc3	dph	0,dpbpc3	;,64,91

;These are for drives E: and F: default to IBM3740

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init4
	db	4,0		; relative drive four
fdsd0	dph	0,dpbpc4	;sdtran,dpbsd	

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init5
	db	5,0		; relative drive five
fdsd1	dph	0,dpbpc5	;sdtran,dpbsd	

;These are for drives G: and H: default to PC1440
	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init6
	db	6,0		; relative drive six
fdpc6	dph	0,dpbpc6	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init7
	db	7,0		; relative drive seven
fdpc7	dph	0,dpbpc7	;,64,91

;These are for drives I: and J: default to z80sim HD4MB

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init8
	db	8,0		; relative drive eight
hd4m0	dph	0,dpbpc8	;0,dpbhd4	

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init9
	db	9,0		; relative drive nine
hd4m1	dph	0,dpbpc9	;0,dpbhd4	

;These are for drives K: L: M: N: O: default to PC1440
	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init10
	db	10,0		; relative drive ten
fdpc10	dph	0,dpbpc10	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init11
	db	11,0		; relative drive eleven
fdpc11	dph	0,dpbpc11	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init12
	db	12,0		; relative drive twelve
fdpc12	dph	0,dpbpc12	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init13
	db	13,0		; relative drive 13
fdpc13	dph	0,dpbpc13	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init14
	db	14,0		; relative drive 14
fdpc14	dph	0,dpbpc14	;,64,91

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init15
	db	15,0		; relative drive 15
fdpc15	dph	0,dpbpc15	;,64,91

	
	cseg	; DPB must be resident


; pc8190's


dpbpc0	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift

dpbpc1
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift

dpbpc2
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift

dpbpc3
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc4
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc5
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc6
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc7
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc8
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc9
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc10
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc11
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc12
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc13
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift
dpbpc14
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift

dpbpc15
	dw	72		;spt
	db	5		;bsh
	db	31		;blm
	db	1		;exm
	dw	2042		;dsm
	dw	2047		;drm
	db	0ffh		;al0
	db	0ffh		;al1
	dw	512		;cks
	dw	2		;off
	DB	0,0		;physical sector size and shift


	dseg	; rest is banked

dpbsd	dpb 128,26,77,1024,64,2

;default drive parametr block for pc1440
;dpb 128,72,160,2048,256,2
dpbpc	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

;default drive parametr block for 4mb z80sim
dpbhd4
	DW    128		;sectors per track
	DB    4			;block shift factor
	DB    15		;block mask
	DB    0			;extent mask
	DW    2039		;disk size-1
	DW    1023		;directory max
	DB    255		;alloc 0
	DB    255		;alloc 1
	DW    256		;check size
	DW    0			;track offset
	DB    0,0		;physical sector size and shift

sdtran	skew 26,6,1
;pctran	skew 72,1,1 ;this not needed with modified BIOSKRNL.ASM 
				;that returns one based sector numbers in sectrans

    ; Disk I/O routines for standardized BIOS interface

; Initialization entry point.

;		called for first time initialization.


fd$init0:
fd$init1:	; all initialization done by Emulator
fd$init2:
fd$init3:
fd$init4:
fd$init5:
fd$init6:
fd$init7:
fd$init8:
fd$init9:
fd$init10:
fd$init11:
fd$init12:
fd$init13:
fd$init14:
fd$init15:
	ret

; enter with HL pointing to NDI data

feedNDI:
again	mov	a,m	;got size 1=low 2=low/high and FF=finished
	cpi	0ffh
	jz	finish
	cpi	2
	jrz	do2
do1	inx	hl
	mov	a,m	;got register selector in a
	out	0cah	;out to select port
	inx	hl
	mov	a,m	;got value to out to register
	out 	0c8h	; out to low reg
	inx	hl
	jr 	again
do2	inx	hl
	mov	a,m	;got register selector in a
	out	0cah	;out to select port
	inx	hl
	mov	a,m	;got value to out to low register
	out 	0c8h	; out to low reg
	inx	hl
	mov	a,m	;got value to out to high register
	out 	0c9h	; out to high reg
	inx	hl
	jr 	again
finish
	ret
; disk READ and WRITE entry points.

		; these entries are called with the following arguments:

			; relative drive number in @rdrv (8 bits)
			; absolute drive number in @adrv (8 bits)
			; disk transfer address in @dma (16 bits)
			; disk transfer bank	in @dbnk (8 bits)
			; disk track address	in @trk (16 bits)
			; disk sector address	in @sect (16 bits)
			; pointer to XDPH in <DE>

		; they transfer the appropriate data, perform retries
		; if necessary, then return an error code in <A>


;read/write addresses above boundry to/from bank 0 (common)

;read sector

fd$read:
	sded	dt$ptr
	mvi	a,cmd$read
	push	a		;save cmd on stack
	jr	dsk$com		;perform operation

;write sector

fd$write:	
	sded	dt$ptr
	mvi	a,cmd$write
	push 	a		;save cmd on stack
	jr	dsk$com		;perform operation

;disk executive

dsk$com:

;	New Disk Interface

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

	mvi	a,011h	;select DMA bank
	out	0cah	;disk reg select
	lda	@dbnk	
	out	0c8h

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

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

	mvi	a,024h	;select sector
	out	0cah	;disk reg select
	lda	@sect
	out	0c8h	;dsk$secL

; the folowing code is added to allow those improperly written programs
; that call bios directly but assume 8 bit sector numbers to work (like-copysys.com)
	call	spt$val	;get SPT value
	mov	a,d	;see if 8bit
	ora	a
	jrz	out$hi	;if 8bit then hi byte =0
; end of fix for 8bit errors

	lda	@sect+1	
out$hi	out	0c9h	;dsk$secH

	mvi	a,000h	;select Command
	out	0cah	;disk reg select
	pop	a	;retrieve from stack
	out	0c8h	;dsk$cmd

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

	ana	a	;set ccr
	ret


;get DPB address returned in DE

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

;get SPT returned in DE

spt$val	call	dpb$ad
	xchg
	mov	e,m
	inx	h
	mov	d,m
	ret

NDI$NDI	equ	20h
DPB$NDI	equ	08h

DPB$IDT equ	20h

DPBsize	equ	17	;15 for CPM2

magic	db	'NDI-Z80E'
mag$sz	equ	$-magic

id1440	db	'3.5 1440'
id$sz	equ	$-id1440

mag$trk	equ	0
mag$sec	equ	5

dt$ptr DW	0

ibm8P:
	set8	080h,0	;order
	set8	081h,0	;formatType
	set8 	082h,0	;DONT use prepost

	set16	09ah,0	;IDM flag	0

	set16	0a0h,77	;Cylinders
	set8	0a1h,1	;Heads

	set8	0a3h,1	;density	(data) 	Single=1
	set16	0a4h,26	;SPT		(data) 
	set8	0a5h,0	;Sector Size	(data) 	128
	set8	0a6h,2	;clock		(data) 	8inch=2

	db	0ffh
UMHD4P:
	set8	080h,0		;order
	set8	081h,0		;formatType
	set8 	082h,0		;DONT use prepost

	set16	09ah,0		;IDM flag	0

	set16	0a0h,255	;Cylinders
	set8	0a1h,1		;Heads

	set8	0a3h,0		;density	(data) 	Don't care
	set16	0a4h,128	;SPT		(data) 
	set8	0a5h,0		;Sector Size	(data) 	128
	set8	0a6h,1		;clock		(data) 	HD

	db	0ffh
PC1440P:
	set8	080h,0		;order
	set8	081h,0		;formatType
	set8 	082h,0		;DONT use prepost

	set16	09ah,0		;IDM flag	0

	set16	0a0h,80		;Cylinders
	set8	0a1h,2		;Heads

	set8	0a3h,2		;density	(data) 	Double=2
	set16	0a4h,72		;SPT		(data) 
	set8	0a5h,0		;Sector Size	(data) 	128=0
	set8	0a6h,4		;clock		(data) 	3inch=4

	db	0ffh

log$NDI
	set16	10h,log$buff
	set8	11h,0ffh	;default bank
	set16	22h,mag$trk
	set16	24h,mag$sec
	set8	00h,cmd$log	
	db	0ffh

ret

fd$login:	; This entry is called when a logical drive is about to
		; be logged into for the purpose of density determination.

		; It may adjust the parameters contained in the disk
		; parameter header pointed at by <DE>

	sded	dt$ptr

	;read disk definition from drive into log buffer

	mvi	a,018h	;select Drive
	out	0cah	;disk reg select

	lda	@rdrv
	out	0c8h	;dsk$drv

	lxi	h,log$NDI
	call	feedNDI

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

	ana	a	;set ccr
	rnz		;do nothing if not readable (sector 5)

;check for magic for DD (disk Definition)

	lxi	h,log$buff	;get address of log buffer
	lxi	d,magic		;de points to DD magic value
	mvi	b,mag$sz	;magic size
	call	strncmp		;check for Magic DD
	jz	its$DD		; matched DD id magic

	lxi	h,log$buff	;get address of log buffer
	lxi	d,id1440	;de points to IDT magic value
	mvi	b,id$sz		;magic size
	call	strncmp		;check for Magic DD
	jz	its$IDT		; matched IDT id magic

; if niether Magic matches
; set to A:-D: toPC1440  E:-F: to IBM  I:-J: to z80sim 4mb

its$def
	lda	@rdrv		;0-3  ABCD
	cpi	4
	jc	SetPC1440

	cpi	6		;4-5  EF
	jc	SetIBM

	cpi	8		;6-7 GH
	jc	SetPC1440

	cpi	10		;8-9 IJ
	jc	Set4MB		
	
	cpi	16		;10-15 KLMNO
	rnc			;SetPC1440

SetPC1440
	lxi	hl,PC1440P	;hl should be pointer to NDI disk definition data
	call	Def$Disk	;move NDI info to NDI 
	lxi	hl,dpbpc		;hl=internal DPB
	call	cpyDPB
	jr	CLR$XLT
SetIBM
	lxi	hl,ibm8P	;hl should be pointer to NDI disk definition data
	call	Def$Disk	;move NDI info to NDI 
	lxi	hl,dpbsd		;hl=internal DPB
	call	cpyDPB
	lxi	de,sdtran
	jr	SET$XLT
Set4MB
	lxi	hl,UMHD4P	;hl should be pointer to NDI disk definition data
	call	Def$Disk	;move NDI info to NDI 
	lxi	hl,dpbhd4		;hl=internal DPB
	call	cpyDPB
	jr	CLR$XLT

its$IDT
	lxi	hl,PC1440P	;hl should be pointer to NDI disk definition data
	call	Def$Disk	;move NDI info to NDI 

	; copy DPB from log Buffer to real DPB

	call	dpb$ad			;de=DPB in bios
	lxi	hl,log$buff+DPB$IDT	;hl=internal DPB
	lxi	b,DPBsize-2		;size of dpb-2 because IDT is CPM2.2
	ldir
	xra	a		;clear PHM and PSH
	mov	m,a
	inx 	hl
	mov	m,a
	jr	CLR$XLT

its$DD
	lxi	hl,log$buff+NDI$NDI	;hl should be pointer to NDI disk definition data
	call	Def$Disk		;move NDI info to NDI 

	; copy DPB from log Buffer to real DPB

	lxi	hl,log$buff+DPB$NDI	;hl=internal DPB
	call	cpyDPB

; clear XLT because PCxxxx Z80 disks don't need it.
CLR$XLT	lxi	de,0
SET$XLT
	lhld	dt$ptr 	;ptr to dph
	mov	m,e
	inx	h
	mov	m,d	
	ret

cpyDPB	
	; copy default DPB to real DPB
	;hl=new DPB
	call	dpb$ad			;de=DPB in bios
	lxi	b,DPBsize		;size of dpb
	ldir
	ret

; load disk config from disk definition table
; this routine writes new disk config data from login buffer
;   to the Z80 Emulator's Disk Controller config registers

Def$Disk:

;select drive

	mvi	a,018h	;select
	out	0cah	;out to select drive port
	lda	@rdrv
	out	0c8h	; out to low reg

; hl should be pointer to NDI disk definition data
	call 	feedNDI	; config the disk

;set parameters
	mvi	a,000h	;select command Reg
	out	0cah	;out to select port
	mvi	a,07fh	;command is NULL but causes parameters to be set
	out	0c8h	; out to low reg
;fall though to ret
fd$nolog:
	ret

strncmp
scloop	ldax	d		;get magic character
	cmp	m		;match?
	rnz			;no - return doing nothing
	inx	h		;point to next chars
	inx	d		;
	dcr	b		;dec count of characters
	jrnz	scloop		;again
	ret

log$buff ds 128

	end
