	title 'PROF-80 Multi density diskette handler'

;    CP/M-80 Version 3     --  Modular BIOS

;	Disk I/O Module for PROF-80

	;		Letzte Aenderung am 24.11.1984 (Joachim)

	dseg

    ; Disk drive dispatching tables for linked BIOS

	public	fdsd0,fdsd1,fdsd2,fdsd3


    ; Variables containing parameters passed by BDOS

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

    ; 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
	extrn	?bank

    ; Utility routines in PROF-80 BIOS

	extrn	monon,monoff



	maclib cdef
;
	maclib cpm3
;
	maclib z80
;
	maclib monvec
;
	maclib syspage

    ; common control characters

cr	equ 13
lf	equ 10
bell	equ 7


    ; Extended Disk Parameter Headers (XPDHs)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init
	db	0,0		; relative drive zero
fdsd0	dph     skew8,dp8d3a,64,144

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init0
	db	1,0		; relative drive one
fdsd1	dph	skew8,dp8d3a,64,144

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init0
	db	2,0		; relative drive two
fdsd2	dph	skew8,dp8d3a,64,144

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init0
	db	3,0		; relative drive three
fdsd3	dph	skew8,dp8d3a,64,144

	cseg	; DPB must be resident

dp8s0	dpb 128,26,77,1024,64,2
dp8d3	dpb 1024,8,77,2048,128,2
dp8d1a	dpb 256,52,77,4096,128,2
dp8d2a	dpb 512,30,77,2048,256,2
dp8d3a	dpb 1024,16,77,8192,256,2
dp5d1	dpb 256,16,40,1024,64,4
dp5d2	dpb 1024,5,40,1024,64,3
dp5d3	dpb 1024,5,80,2048,128,3
dp5d2a	dpb 512,20,40,2048,128,3
dp5d3a	dpb 512,20,80,2048,128,3

	dseg

skew26	skew	26,6,1
	skew1	26,6,1

skew15	skew	15,4,1
	skew1	15,4,1

skew8	skew	8,3,1
	skew1	8,3,1

skew5	skew	5,1,1
	skew1	5,1,1

skew10	skew	10,2,1
	skew1	10,2,1

noskew	skew	16,1,1



    ; Disk I/O routines for standardized BIOS interface

; Initialization entry point.

;		called for first time initialization.


fd$init:
	lxi	h,disk$type$list	; setze Zeiger auf
	shld	typelist		; disk$type$list
fd$init0:
	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>

	push	d		; save pointer to dph
	call	test$format	; test disk format
	pop	d		; get back dph pointer
	cpi	0ffh		; disk not correct
	jrz	disk$not$korr	; dann sprung
	lxi	h,-1		; zeiger auf drive typ
	dad	d		;
	mov	m,a		; setze drive type in xdph
	mov	l,a		; setze dph
	mvi	h,0		;
	dad	h		;
	dad	h		;
	dad	h		;
	lxi	b,disk$type$list+4
	dad	b		; hl zeigt auf dpb adr
	push	h		;
	exx			; zweitregistersatz
	pop	h		;
	mov	c,m		;
	inx	h		;
	mov	b,m		;
	inx	h		;
	mov	e,m		;
	inx	h		;
	mov	d,m		;
	exx			;
	push	d		; dph adr. in zweitregister
	exx			;
	pop	h		;
	mov	m,e		;
	inx	h		;
	mov	m,d		;
	lxi	d,11		;
	dad	d		;
	mov	m,c		;
	inx	h		;
	mov	m,b		;
	exx			;
	ret			;
disk$not$korr:
	; setze stack so, dass hl=0 wenn seldsk zum bdos zurueckkehrt
	pop	d	; returnadresse
	pop	h	; dph adresse
	lxi	h,0	; setze dph adresse auf 0 (platte nicht erkennbar)
	push	h	; stack wieder herstellen
	push	d	;
	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>
fd$write:
	mvi	a,0ffh
	jr	rwcom


fd$read:
	xra	a
rwcom:
	sta	roderw		; read oder write
	xchg			; save dph adress
	shld	current$dph
more$retries:
	mvi	a,0ffh		; unterdruecke fehlermeldung
	sta	dermsg
	mvi	a,5		; fuenf versuche
	sta	rwretry
	
	call	rwcom1		; lesen und schreiben von common

	ora	a		; fehler?
	jrz	rwcom3		; sprung wenn nein
	lda	rest+1		; write protect?
	ani	2		;
	jrnz	rwcom3		; ja, fehlercode 2 (zufall)
	call	test$format	; format geaendert?
	lhld	current$dph
	dcx	h
	cmp	m		; format gleich ?
	mvi	a,0ffh
	jrnz	rwcom3		; sprung wenn formatwechsel
	lda	@ermde		; fehlermeldung zugelassen?
	sta	dermsg

	call	rwcom1		; zweiter lese-schreib-versuch

	ora	a
	jrz	rwcom3
	lda	@ermde
	ora	a
	jrnz	rwcom6
	lxi	h,retrymsg
	call	?pmsg
	call	conin$echo
	cpi	'Y'
	jrz	more$retries
rwcom6	mvi	a,1
rwcom3	ret

conin$echo:
	call	?conin
	push	psw
	mov	c,a
	call	?cono
	pop	psw
	cpi	'a'
	rc
	sui	'a'-'A'
	ret

retrymsg:
	db	10,13,' Retry (Y/N) ?',0


setup:
	; setze alle parameter in CMDTAB
	; setze 9229 auf mini/maxi betrieb

	lhld	current$dph	; zeiger auf plattentyp setzen
	xchg			;
	lxi	h,-1		;
	dad	d		;
	mov	l,m		; zeiger auf disk$type$list eintrag
	mvi	h,0		;
	dad	h		;
	dad	h		;
	dad	h		;
	lxi	b,disk$type$list;
	dad	b		;
	mov	a,m		;
	ani	20h		; setze auf mini/maxi
	jrz	setup1		;
	call	miniset		;
	jr	setup2		;
setup1	call	maxiset		;
setup2	mov	a,m		; setze diskformat in cmdtab
	mov	c,a		;
	ani	40h		; setze mfm bit
	sta	cmdtab		;
	mov	a,c		; setze sektorgrroesse
	ani	00000011b	;
	sta	secsz		;
	ora	a		; setze dtl
	mvi	a,0ffh		;
	jrnz	setup3		;
	mvi	a,80h		;
setup3	sta	dtll		;
	inx	h		; setze eot
	mov	a,m		;
	sta	eot		;
	inx	h		; setze gap laenge
	mov	a,m		;
	sta	gapll		;
	inx	h		; setze write precompensation
	mov	a,m		;
	sta	write$precom	;
	lda	@rdrv		; laufwerk
	ani	00000011b	;
	sta	unit		;
	lda	@trk		; spur
	sta	track		;
	lhld	@sect		; sektor
	mov	a,l		;
	ani	01111111b	; blende head bit aus
	sta	sector		;
	xra	a		; head
	sta	head		;
	mov	a,l		;
	ani	80h		; war es die zweite seite
	rz			; dann zurueck
	mvi	a,1		;
	sta	head		;
	ret			;

miniset:
	push	psw
	mvi	a,pad$mini or 1
	out	p$ls259
	pop	psw
	ret

maxiset:
	push	psw
	mvi	a,pad$mini
	out	p$ls259
	pop	psw
	ret

	cseg

rwcom1:
	call	setup		; lese-schreib-kern
	call	setmem		; muss in common liegen
	call	monon
	lda	roderw
	ora	a
	jrz	rwcom2
	call	mwrite
	jr	rwcom5
rwcom2	call	mread
rwcom5	call	monoff
	push	psw
	call	bank0
	pop	psw
	ret

setmem:
	; setze kacheln fuer uebertrag
	; und dmaadresse
	mvi	a,1		; ein sektor uebertragen
	sta	sectcnt		;
	lhld	@dma		; lese dma adresse
	mvi	a,2ah		; unter 3000h ?
	cmp	h		;
	jrnc	setmem1		; wenn ja, sprung
	shld	dmaadr		; trage dmaadresse ein
	lda	@dbnk		; setze dmabank
	call	?bank		;
	ret			;
setmem1	lxi	d,8000h		; addiere 8000h zu dmaadresse
	dad	d		;
	shld	dmaadr		;
				; lege untere 3 kacheln nach 8000h
	mvi	b,80h		;
	mvi	c,p$ram$table	;
	lda	@dbnk		; schalte gewuenschte bank nach 8000h
	adi	2		;
	outp	a		;
	mvi	b,90h		;
	outp	a		;
	mvi	b,0a0h		;
	outp	a		;
	ret			;

bank0
	lda	@cbnk		; setze alte bank
	call	?bank		;
	ret

roderw	ds	1

	dseg			; rest is banked


TEST$FORMAT:
	;TESTET DAS FORMAT DER DISK, DIE SICH IM VON
	;SEKDSK	SPEZIFIZIERTEN LAUFWERK BEFINDET UND VERGLEICHT
	;ES MIT DEN IN DISK$TYPE$LIST ERLAUBTEN FORMATEN.
	;IST DAS FORMAT NICHT ERKENNBAR, ODER IN DISK$TYPE$LIST
	;NICHT VEREINBART, SO KEHRT TEST$FORMAT MIT AKKU=0FFH
	;ZURUECK. KONNTE DAS FORMAT ERMITTELT WERDEN UND WAR ES AUCH IN
	;DISK$TYPE$LIST VEREINBART, DANN KEHRT TEST$FORMAT MIT AKKU=0
	;ZURUECK. IN DIESEM FALL WIRD IN ABHAENIGKEIT VON SEKDSK
	;DER DISK-TYP IN DISKTYPA, -B, -C ODER -D NEU GESETZT
	;DER DISK-TYP ENTSPRICHT DER LAUFENDEN NUMMER DES EINTRAGS
	;IN DER DISK$TYPE$LIST TABELLE.
	;
	lda	@rdrv		;SETZE DAS ZU TESTENDE LAUFWERK
	ani	03h		;maskiere die oberen 6 bits
	STA	UNIT		;
	MVI	B,5		;FUENF TEST-VERSUCHE
	MVI	A,1		;AUF SPUR 1
	STA	TEST$TRACK	;
TESTF1:	PUSH	B		;
	CALL	monon		;BENUTZE TEST-PROGRAMM
	CALL	mtest		;AUS MONITOR
	CALL	monoff		;
	POP	B		;
	ORA	A		;WAR TEST ERFOLGREICH ?
	JRZ	TESTF3		;SPRUNG WENN JA
	DJNZ	TESTF1		;SONST MAXIMAL FUENF VERSUCHE
TESTF2	MVI	A,0FFH		;SONST RUECKSPRUNG MIT AKKU=0FFH
	RET			;
TESTF3:				;OK, FORMAT DATEN STEHEN IN TEST$TYPE
				;UND TEST$TRACK
	MVI	B,0		;ZAEHLER FUER DISKTYP
	LDA	TEST$TYPE	;TYPE IN D
	MOV	D,A		;
	LDA	TEST$MSEK	;SECTORGROESSE IN E
	MOV	E,A		;
	LXI	H,DISK$TYPE$LIST;ZEIGER AUF VEREINBARTE FORMATE
TESTF4:	MOV	A,M
	ANI	010H		;ENDE DER LISTE
	JRNZ	TESTF2		;DANN MIT FEHLER-MELDUNG ZURUECK
	MOV	A,M		;VERGLEICHE EINTRAG MIT DE
	CMP	D		;IST TYP GLEICH?
	JNZ	INX8		;NEIN EINEN EINTRAG WEITER
	INX	H		;TYP WAR GLEICH
	MOV	A,M		;STIMMT AUCH NOCH DIE SEKTORGROESSE
	CMP	E		;
	JNZ	INX7		;NEIN EINEN EINTRAG WEITER
				;
				;OK, DISK WURDE ERKANNT
	mov	a,b		;
	RET			;
				;
INX8	INX	H		;EINEN DISK-TYP WEITER
INX7	INX	H		;
	INX	H		;
	INX	H		;
	INX	H		;
	INX	H		;
	INX	H		;
	INX	H		;
	INR	B		;
	JR	TESTF4		;


;********************************************************************
;
;HIER WERDEN DIE MOEGLICHEN DISK-FORMATE VEREINBART
;
;
;
DISK$TYPE$LIST:
	;
	;DIESE LISTE DEFINIERT DIE VOM BETRIEBSSYSTEM LESBAREN
	;PLATTEN-TYPEN
	;DIE LISTE BESTEHT AUS BELIEBIG VIELEN EINTRAEGEN VON
	;JE ACHT BYTE, DIE WIE NACHFOLGEND BESCHREIBEN AUFGEBAUT
	;SIND:
	;	BYTE 1	:DISK-TYP WIE VON MONTEST ERMITTELT
	;	BYTE 2	:SEKTOR-ANZAHL
	;	BYTE 3	:GAP-LAENGE DIE DER UPD 765 VERWENDEN SOLL
	;	BYTE 4	:WRITE PRECOMPENSATION
	;	BYTE 5-6:ADRESSE DES DPB FUER DIESES FORMAT
	;	BYTE 7-8:ADRESSE DER SEKTOR SKEW-TABLE
	;
	;TEST$FORMAT VERGLEICHT DIE BEIDEN ERSTEN BYTES MIT
	;TEST$TYPE UND TEST$MSEK DIE DAS UNTERPROGRAM MONTEST
	;LIEFERTT.
	;
	SSIDE	EQU	000H	;EQUATES FUER TYPE
	DSIDE	EQU	080H	;
	SDENS	EQU	000H	;
	DDENS	EQU	040H	;
	MAXIF	EQU	000H	;
	MINIF	EQU	020H	;
	S0128	EQU	000H	;
	S0256	EQU	001H	;
	S0512	EQU	002H	;
	S1024	EQU	003H	;
	;
	;
	DB	SSIDE OR SDENS OR MAXIF OR S0128
	DB	26
	DB	07,0
	DW	DP8S0,SKEW26
	;
	DB	SSIDE OR DDENS OR MAXIF OR S1024
	DB	8
	DB	35H,2
	DW	DP8D3,SKEW8
	;
	DB	DSIDE OR DDENS OR MAXIF OR S0256
	DB	26
	DB	7,2
	DW	DP8D1A,SKEW26
	;
	DB	DSIDE OR DDENS OR MAXIF OR S0512
	DB	15
	DB	18H,2
	DW	DP8D2A,SKEW15
	;
	DB	DSIDE OR DDENS OR MAXIF OR S1024
	DB	8
	DB	35H,2
	DW	DP8D3A,SKEW8
	;
	DB	SSIDE OR DDENS OR MINIF OR S0256
	DB	16
	DB	1BH,2
	DW	DP5D1,NOSKEW
	;
	DB	SSIDE OR DDENS OR MINIF OR S1024
	DB	5
	DB	1BH,2
	DW	DP5D2,SKEW5
	;
	DB	DSIDE OR DDENS OR MINIF OR S1024
	DB	5
	DB	1BH,2
	DW	DP5D3,SKEW5
	;
	DB	SSIDE OR DDENS OR MINIF OR S0512
	DB	10
	DB	0EH,2
	DW	DP5D2A,SKEW10
	;
	DB	DSIDE OR DDENS OR MINIF OR S0512
	DB	10
	DB	0EH,2
	DW	DP5D3A,SKEW10
	;
	DB	010H		;ENDE-KENNUNG

current$dph	ds	2	

	end
