	title	'WD1010 Winchester Controller Driver fuer PROF-181X'

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

	;	Alle verwendeten Parameter sind fuer eine Winchester
	;	NEC D3142, 8 Koepfe, ausgelegt

	;Laufwerk-Tabellen fuer BIOS-I/O

	public	hdsk0,hdsk1,hdsk2

	;Parameter aus dem BDOS/BIOS

	extrn	@dma,@dtbl		;DMA-Adresse u. Laufwerkstabelle
	extrn	@trk,@sect		;Spur- u. Sektor-Nummer
	extrn	@dbnk,@cbnk		;Daten- u. Common-Bank-Nummer

	;System Control Block Variables

	extrn	@ermde			;BDOS Fehlermeldungs-Modus

	;Utility-Routinen aus dem Standard-BIOS

	extrn	?pmsg			;Print Message
	extrn	?pderr			;Print BIOS Disk Error Header
	extrn	?bank			;Bank Select Routine

	;HD64180 Macro Library Instruction Definitions

	maclib	HD64180

	;Port-Adressen der Hard-Disk-Karte/Controller

hdcbase	equ	0a8h			;Basis Adresse des Controllers
hdcdat	equ	hdcbase			;Datenregister
hdcerr	equ	hdcbase+1		;(r) Error Register
hdcwpc	equ	hdcbase+1		;(w) Write-Precompensation Start
hdcsek	equ	hdcbase+3		;Sektor Register
hdccyl	equ	hdcbase+4		;Low Byte des Zylinders
hdccyh	equ	hdcbase+5		;High Byte des Zylinders
hdcsdh	equ	hdcbase+6		;Sdh-Register
hdccmd	equ	hdcbase+7		;(w) Command Register
hdcsta	equ	hdcbase+7		;(r) Status Register

	;Allgemeine Equals

cr	equ	13
lf	equ	10
bell	equ	7

	;Controller-Kommandos

c$rest	equ	10h			;Restore Drive (Recalibrieren)
c$read	equ	20h			;Lesekommando (ohne Retry)
c$write	equ	30h			;Schreibkommando (ohne Retry)

	;physikalische Definitionen der Harddisk. Diese Parameter muessen
	;an das gewaehlte Format und Laufwerk angepasst werden.

wpvalue	equ	32			;Begin der Precompensation
secsiz	equ	1024			;Sektorgroesse in Bytes
secmask	equ	0100$0000b		;Codierung der Sektorgroesse
heads	equ	8			;Anzahl Koepfe (muss Vielfaches von 2 sein)

	;Statusbit Maske

drqflg	equ	8			;Data Request

	;Select-Deselect-Maskierung (1=select)

selmask	equ	8			;LW selektieren
desmask	equ	0			;und deselektieren

	;Extended Disk Parameter Headers (XDPH)

	dseg

	dw	hd$write		;Schreiben auf Harddisk
	dw	hd$read			;Lesen von Harddisk
	dw	hd$login		;Ein"loggen" der Harddisk
	dw	hd$init0		;gesamte HD im Boot initialisieren
	db	0			;relative LW-Nummer
	db	0			;Disk-Modus
hdsk0:	dw	0			;Skew-Table (noskew)
	db	0,0,0,0,0,0,0,0,0	;BDOS Scratch Area
	db	0			;Media Flag (0=kein Plattenwechsel)
	dw	dpb0			;Disk Parameter Block
	dw	0			;Checksum Vector (0=keine Ueberpruefung)
	dw	0fffeh			;Allocation Vector (setzt GENCPM)
	dw	0fffeh,0fffeh,0fffeh	;Dirbcb,Dtabcb,Hash alloc'd (setzt GENCPM)
	db	0			;Hash Bank
	dw	0			;Checksum Vector

	dw	hd$write
	dw	hd$read
	dw	hd$login
	dw	hd$init1
	db	0
	db	0
hdsk1:	dw	0
	db	0,0,0,0,0,0,0,0,0
	db	0
	dw	dpb1
	dw	0
	dw	0fffeh
	dw	0fffeh,0fffeh,0fffeh
	db	0
	dw	0

	dw	hd$write
	dw	hd$read
	dw	hd$login
	dw	hd$init1
	db	0
	db	0
hdsk2:	dw	0
	db	0,0,0,0,0,0,0,0,0
	db	0
	dw	dpb2
	dw	0
	dw	0fffeh
	dw	0fffeh,0fffeh,0fffeh
	db	0
	dw	0

	;Disk Parameter Block (DPB)

	cseg

dpb0:	dw	72		;128 byte records per track (1024 * 9)/128
	db	5,31		;block shift and mask (4096)
	db	1		;extent mask
	dw	3851		;maximum block number [(dpb1offs-dpb0offs)/4*9]-1
	dw	2047		;maximum directory entry number (4096/2)-1
	dw	0ffffh		;alloc vector for directory
	dw	8000h		;checksum size
	dw	0		;offset for system tracks
	db	3,7		;physical sector size and shift (1024)

dpb1:	dw	72
	db	5,31
	db	1
	dw	3851
	dw	2047
	dw	0ffffh
	dw	8000h
	dw	1712
	db	3,7

dpb2:	dw	72
	db	5,31
	db	1
	dw	3851
	dw	2047
	dw	0ffffh
	dw	8000h
	dw	3424
	db	3,7

	;Harddisk I/O-Routinen

	;Initialisierung wird im Boot vorgenommen
	;Bei der Initialisierung wird ein Restore Drive Kommando abgesetzt
	;und in Abhaengigkeit der Controller-Meldungen ein Fehler-Bit gesetzt

	dseg

hd$init0:
	call	restore
	lxi	h,resterror
	jrc	hd$init2
	mvi	a,wpvalue
	out	hdcwpc
hd$init2:
	jrnc	hd$init3
	lxi	d,0
	sded	@dtbl+2
	sded	@dtbl+4
	sded	@dtbl+6
hd$init3:
	cc	?pmsg
	jp	hd$exit
hd$init1:
	ret

	;Kein login noetig

hd$login:
	ret

	;Lese-/Schreib-Routinen

hd$read:
	mvi	a,2
hd$read1:
	push	psw
	lxi	h,read$msg
	shld	operation$name
	call	uptask
	mvi	a,c$read
	out	hdccmd
	call	busy
	jrc	rd$error
	pop	psw
	call	waitdrq
	call	hdtrans1
	jmp	hd$exit
rd$error:
	call	cleardrq
	pop	psw
	dcr	a
	jrnz	hd$read1
	jmp	hd$error

hd$write:
	mvi	a,2
hd$write1:
	push	psw
	lxi	h,write$msg
	shld	operation$name
	call	uptask
	mvi	a,c$write
	out	hdccmd
	call	waitdrq
	call	hdtrans2
	call	busy
	jrc	wr$error
	pop	psw
	jmp	hd$exit
wr$error:
	pop	psw
	dcr	a
	jrnz	hd$write1
	jmp	hd$error

	;Setzen des Task-Registers
	;Dem BIOS/BDOS praesentiert sich die Harddisk als
	;"Disklaufwerk" mit einem Kopf und einer entsprechend
	;grossen Anzahl Spuren. Daher muss in der folgenden
	;Routine die physikalische Sektor-Kopf-Spurinformation
	;aus der logischen Sektor-Spurinformation genommen
	;werden. Dabei kann fuer Partitionen die gleiche
	;Routine verwendet werden, da sie fortlaufende
	;Spurnummern verwenden. Die erste Spur der zweiten
	;Partition ist die auf die letzte Spur der ersten Partition
	;folgende. Dies wurde durch einen entsprechenden System-
	;Track-Offset erreicht. (DPB)
	;Man kann allerdings die Selektion der verschiedenen
	;Partitionen auch ueber @rdrv, relative drive number, die
	;im DPH angegeben ist, vornehmen. In diesem Fall besteht
	;auch eine einfache Moeglichkeit, mit z.B 6-Koepfen zu
	;arbeiten.

uptask:
	call	cleardrq
	lda	@sect
	out	hdcsek
	lda	@trk
	ani	heads-1
	ori	secmask or selmask
	out	hdcsdh
	lda	@trk
	mov	b,a
	lda	@trk+1
	srlr	a
	rarr	b
	if heads > 2
	srlr	a
	rarr	b
	if heads > 4
	srlr	a
	rarr	b
	endif
	endif
	out	hdccyh
	mov	a,b
	out	hdccyl
	ret

	;Loeschen anliegender Data-Requests

cleardrq:
	in	hdcsta
	ani	drqflg
	rz
	in	hdcdat
	jr	cleardrq

	;Warte, bis DRQ aktiv wird

waitdrq:
	in	hdcsta
	ani	drqflg
	rnz
	jr	waitdrq

	;Warte, bis Kommando fertig abgearbeitet ist

busy:
	in	hdcsta
	ana	a
	jm	busy
	rar
	ret

	;Controller- und Laufwerks-Initialisierung
	;Es wird geprueft, ob der Controller nicht busy ist
	;Ist dieses der Fall, wird das Restore-Kommando abgesetzt
	;und auf kein busy, kein error gewartet
	;Geschieht dies nicht innerhalb einer angemessenen Frist,
	;wird das Laufwerk als fehlerhaft zurueckgemeldet. Bei
	;langsam hochfahrenden Laufwerken ist ggf. der Zaehler
	;innerhalb der Wait-Routine zu erhoehen

restore:
	mvi	a,selmask
	out	hdcsdh
	call	wait
	mvi	a,desmask
	out	hdcsdh
	call	wait
	mvi	a,secmask
	ori	selmask
	out	hdcsdh
	lxi	h,-5
	call	restore0
	rc
	call	cleardrq
	mvi	a,0
	out	hdccyl
	out	hdccyh
	out	hdcsek
	mvi	a,c$rest
	out	hdccmd
	lxi	h,-80
restore0:
	in	hdcsta
	ana	a
	jm	restore1
	rar
	ret
restore1:
	call	wait
	lxi	d,1
	dad	d
	jrnc	restore0
	ret

	;Warteschleife fuer Restore

wait:
	push	psw
	push	h
	lxi	h,8000h
wait1:
	dcx	h
	mov	a,h
	ora	l
	jrnz	wait1
	pop	h
	pop	psw
	ret

	;Daten-Uebertragungs-Routinen
	;Einlesen der Daten in den DMA-Puffer

	cseg

hdtrans1:
	lhld	@dma
	di
	lda	@dbnk
	call	?bank
	lxi	b,hdcdat
	rept secsiz/256
	inir
	endm
	jr	hdtrans3
hdtrans2:
	lhld	@dma
	di
	lda	@dbnk
	call	?bank
	lxi	b,hdcdat
	rept secsiz/256
	outir
	endm
hdtrans3:
	lda	@cbnk
	call	?bank
	ei
	ret

	;Fehlerbehandlung
	;Im Fehlerfall wird, sofern das @ermde-Flag entsprechend
	;gesetzt ist, eine ausfuehrliche Fehlermeldung in der Form:
	;BIOS ERR ON D: T=NN, S=MM <Operation> <Type>, RETRY ?
	;ausgegeben. Die Angabe <Type> enthaelt alle im Fehler-Byte
	;des Controllers markierten Errors im Klartext.

	dseg

hd$error:
	lda	@ermde
	cpi	0ffh
	jz	hard$error
	call	?pderr
	lhld	operation$name
	call	?pmsg
	in	hdcerr
	lxi	h,error$table
errm1:
	mov	e,m
	inx	h
	mov	d,m
	inx	h
	add	a
	push	psw
	push	h
	xchg
	cc	?pmsg
	xchg
	pop	h
	pop	psw
	jnz	errm1
hard$error:
	call	hd$exit
	mvi	a,1
	ret

hd$exit:
	mvi	a,desmask
	out	hdcsdh
	xra	a
	ret

	;Tabellen & Messages

read$msg:	db	', READ',0
write$msg:	db	', WRITE',0

operation$name:	dw	read$msg

	;Tabelle der Zeiger auf die detailierten Fehlermeldungen
	;Jede Adresse entspricht einem Fehlerbit des WD1010
	;Start ist Bit 7

error$table:	dw	b7$msg
		dw	b6$msg
		dw	b5$msg
		dw	b4$msg
		dw	b3$msg
		dw	b2$msg
		dw	b1$msg
		dw	b0$msg

b7$msg:		db	', BAD BLOCK',0
b6$msg:		db	', CRC,',0
b5$msg:		db	' ',0
b4$msg:		db	', REC NOT FOUND',0
b3$msg:		db	' ',0
b2$msg:		db	', ABORTED',0
b1$msg:		db	', NO TR000',0
b0$msg:		db	', NO DAM',0

resterror:	db	bell,'** Winchester Drive NOT AVAILABLE **',cr,lf,0

	end
