	title 'MARC Floppy 1024  DOUBLE density diskette handler'

;    CP/M-80 Version 3     --  Modular BIOS

; MARC Version 1.0
; 04.02.90

;	Disk I/O Module based diskette systems

	;	Initial version
	;	DOUBLE density floppy only.
	;	and MEMORY-Disk

	dseg

    ; Disk drive dispatching tables for linked BIOS

	public	fdsd0,fdsd1,fdsd2,fdsd3,fdsd4,fdsd5
	public	fdsd9,fdsd10,fdsdm,fdsd11,fdsd12

	EXTRN	IVDSK1
	extrn	flosta
	EXTRN	FLOPPY,PFTKOM,PFTADR
	EXTRN	ITIMEO,LWEXIS,ALWNR,ASPNR,SPNRL

    ; Variables containing parameters passed by BDOS

	extrn	@adrv,@rdrv
	extrn	@dma,@trk,@sect
	extrn	@dbnk,@cbnk
	EXTRN	@CNT
	extrn	@comon

    ; 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	?xmove,?move

    ; Port Address Equates

	maclib ports

    ; CP/M 3 Disk definition macros

	maclib cpm3

    ; Z80 macro library instruction definitions

	maclib z80

    ; common control characters

cr	equ 13
lf	equ 10
bell	equ 7

;**************************************************************
; VEREINBARUNGEN
;**************************************************************

MAXDSK	EQU	2


    ; Extended Disk Parameter Headers (XPDHs)

; Drive A 780 k

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init0
	db	0,0		; relative drive zero
fdsd0	dph     0,dpbsd

xpdhe0:	db	6,3,1		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive B 780 k

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init1
	db	1,0		; relative drive one
fdsd1	dph	0,dpbsd

	db	6,3,1		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive C 800k (CP/A)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init2
	db	1,0		; relative drive one
fdsd2	dph	0,dpbsdc

	db	6,3,1		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive D 624k

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init3
	db	1,0		; relative drive one
fdsd3	dph	0,dpbsdd

	db	17,1,1		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive E 360k (MSDOS)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init4
	db	1,0		; relative drive one
fdsd4	dph	0,dpbsde

	db	10,2,2		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive F 190k (40 Spuren SS)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init5
	db	1,0		; relative drive one
fdsd5	dph	0,dpbsdf

	db	6,3,2		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive J 171k (Schneider System)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init4
	db	1,0		; relative drive one
fdsd9	dph	0,dpbsdj

	db	10,2,2		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive K 720k (MS-DOS 80-Spuren)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init4
	db	1,0		; relative drive one
fdsd10	dph	0,dpbsdk

	db	10,2,1		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive M RAM-Disk

	dw	fd$writem
	dw	fd$readm
	dw	fd$login
	dw	fd$initm
	db	0,0		; relative drive zero
fdsdm	dph     0,dpbsdm

; Drive N 26*128 (80 Spuren SS)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init5
	db	1,0		; relative drive one
fdsd11	dph	0,dpbsdno

	db	27,0,1		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track

; Drive O 26*128 (80 Spuren SS - Rueckseite)

	dw	fd$write
	dw	fd$read
	dw	fd$login
	dw	fd$init5
	db	1,0		; relative drive one
fdsd12	dph	0,dpbsdno

	db	1,0,1		; ANZ.SEK/2+1,phys.Sekt.len,STP/Track



	cseg	; DPB must be resident

; FUER 80 SPUR-LW:
DPBSD	DPB	1024,10,80,2048,128,2

; fuer CP/A Disketten auf Laufwerk C (simuliert auf B)
DPBSDC	DPB	1024,10,80,2048,192,0

; fuer SCP-Disketten auf Laufwerk D (simuliert auf Laufwerk B)
; 624 K
dpbsdd	dpb	256,32,80,2048,128,2

; fuer MSDOS-Disketten auf Laufwerk E (simuliert auf B)
; 2*40 Spuren 360K
dpbsde	dpb	512,18,40,2048,64,0

; FUER 40 SPUR-LW:
DPBSDF	DPB	1024,5,40,1024,64,2

; fuer Schneider System auf Laufwerk J (simuliert auf B)
; 1*40 Spuren 171K
dpbsdj	dpb	512,9,40,1024,64,2

; fuer MSDOS-Disketten auf Laufwerk K (simuliert auf B)
; 2*80 Spuren 720K
dpbsdk	dpb	512,18,80,2048,64,0

; fuer RAM-Floppy 768 k
dpbsdm	dpb	1024,12,64,2048,128,0

; fuer 26*128 ss
dpbsdno	dpb	128,26,80,2048,64,0

	dseg	; rest is banked


    ; Disk I/O routines for standardized BIOS interface

; Initialization entry point.

;		called for first time initialization.


fd$init0:

	di			; Init im DI

; Port Steuer-A
	lxi	h,itimeo
	shld	ivdsk1
	LXI	H,IVDSK1
	MOV	A,L
	out	fcpioac		; Index-Interrupt
	mvi	a,7fh
	out	fcpioac		; zunaechst Byte-Eingabe
; Port Daten-B
	out	fdpiobc		; Byte Eingabe
	in	fdpiobd		; Scheineingabe
; weiter Steuer A
	mvi	a,11111101b	; AMF aus
	out	fcpioad
	mvi	a,3fh		; ab jetzt Byte Ausgabe
	out	fcpioac		
; Port Daten-A (Schreiben)
	out	fdpioac		; byte-Ausgabe
; Port Steuer-B
	mvi	a,0ffh		; bit E/A
	out	fcpiobc
	mvi	a,0f3h		; eeea aaee
	out	fcpiobc

	ei

; Ermittlung der vorhandenen Laufwerke
	mvi	c,4		; 4 LAUFWERKE WEGEN VESCH.
	mvi	d,0
	mvi	a,0f7h		; ohne lock
flka1:	rlc
	out	fdsel
	exaf
	mvi	b,85		; max 85 mal steppen
flka2:	in	fcpiobd
	rlc			; kam Spur0-Signal?
	jrnc	flka4		; -> ja
	mvi	a,01011111b	; steppen in Richtung Spur 0
	out	fcpioad
	mvi	a,11011111b	; mit Kopf oben
	out	fcpioad
;	lxi	h,1000h
	lxi	h,800H		; Schrittzeit abwarten
flka3:	dcr	l
	jrnz	flka3
	dcr	h
	jrnz	flka3
	djnz	flka2		; -> weiteren Schritt ausfuehren
;****Laufwerke immer existent melden wegen 8" Beistell-Laufwerken ohne Strom
;***	jr	flka5		; -> LW nicht existent
;***
flka4:	setb	6,d		; Laufwerk existent melden
flka5:	dcr	c		; weiteres LW?
	jrz	flka6		; -> nein
	rrcr	d
	rrcr	d
	exaf
	jr	flka1		; -> naechstes LW pruefen

flka6:	mov	a,d
	sta	lwexis

	mvi	a,0ffh		; alle LW ausschalten
	out	fdsel

	xra	a
	sta	alwnr		; LW 0 ist das zuletzt benutzte, Motor ist aus
	sta	aspnr		; steht auf Spur 0
	mvi	b,maxdsk
	lxi	h,spnrl
flka7:	mov	m,a		; alle alten Spurnr. sind 0
	inx	h
	djnz	flka7

fd$init1:			; all initialization done by drive 0
fd$init2:
fd$init3:
fd$init4:
fd$init5:
	ret

; RAM-Disk intialisieren
; Es wird ueberprueft, ob das RAM-Disk-Label aktuell ist,
; wenn ja, so wird keine Initialisierung durchgefuehrt.

fd$initm:
	mvi	a,0		; Spur 0 Sektor 0 lesen
	sta	@trk
	sta	@sect
	sta	@dbnk
	lxi	h,buffer	; nach Buffer
	shld	@dma
	call	fd$readm	; und Sektor lesen
	lxi	h,buffer
	lxi	d,comptex
	mvi	b,28
comp:	ldax	d
	cmp	m
	jrnz	dirkill
	inx	h
	inx	d
	djnz	comp
	ret			; ok, Ramdisk nicht loeschen

dirkill:
	lxi	h,buffer
	lxi	d,buffer+1
	lxi	b,1024-1
rkill:	mvi	m,0
	ldir
	lxi	h,buffer
	mvi	c,8
	lxi	d,20h
leereis:
	mvi	b,3
leerein:
	mvi	m,0e5h
	dad	d
	djnz	leerein
	mvi	m,'!'
	dad	d
	dcr	c
	jrnz	leereis
; Bibliothek schreiben	
	mvi	a,0		; Spur 0 Sektor 0-3 schreiben
	sta	@trk
	sta	@dbnk
nexs:	push	psw
	sta	@sect
	lxi	h,buffer	; nach Buffer
	shld	@dma
	call	fd$writem	; und Sektor schreiben
	pop	psw
	inr	a
	cpi	4
	jrnz	nexs
; aktualisieren Ramdiskeintrag
	lxi	h,comptex
	lxi	d,buffer
	lxi	b,20h
	ldir
	mvi	a,0		; Spur 0 Sektor 0 schreiben
	sta	@trk
	sta	@sect
	sta	@dbnk
	lxi	h,buffer	; nach Buffer
	shld	@dma
	call	fd$writem	; und Sektor schreiben
	ret	

comptex:
	db	' RAMDISK DIRag',0,0
	db	'32/$4*&5',9ch,0fh,18h,0,9ch,0fh,18h,0


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>

	ret	; we have nothing to do in
		;	simple single density only environment.


; RAM-disk READ and WRITE entry points.

adrerz:
	STA	ANZRW
	mvi	a,'M'
	STA	ANZDRV
	LDA	@trk
	CALL	HEXASC
	SHLD	ANZTRK
	LDA	@sect
	CALL	HEXASC
	SHLD	ANZSEK
	LXI	H,ANZEIG
	call	flosta
	lda	@trk	; Berechnen Anfangsbereich der Spur
	ani	3	; auf 64k Speicherseite
	lxi	b,3000h ; auf der Speicherseite bei je 48k
;	lxi	b,4000h	; auf der Speicherseite
	lxi	h,0
	inr	a
nspun:	dcr	a
	jrz	sekb
	dad	b
	jr	nspun
sekb:
	lda	@sect	; und nun den Sektor auf der Spur dazu
	lxi	b,1024
	inr	a
nsekb:	dcr	a
	jrz	sekok
	dad	b
	jr	nsekb
sekok:
	lda	@trk	; Ermittelung der Speicherseite
	rrc
	rrc
	ani	0fh	; max 16 Speicherseiten
	adi	10h	; Beginn ab 1 MByte
;	ani	3	; Spur / 4 => Speicherseite
;	adi	4
;	adi	2	; + 2 Systembaenke
	mov	b,a	; sowohl Zielbank
	mov	c,a	; als auch Quellbank
;
	lded	@dma	; DMA-Adresse fuer Transfer
	push	h
	lhld	@comon
	dcx	h
	ora	a
	dsbc	de
	pop	h
	ret		; cy=1, wenn im common

fd$readm:
	mvi	a,'R'
	call	adrerz	; Berechnen Spur / Sektor
;	mvi	a,1
;	jrc	fd$read1
	lda	@dbnk	; Einstellen der DMA-Bank
;fd$read1:
	mov	b,a
	xchg
	jr	fd$mdma
fd$writem:
	mvi	a,'W'
	call	adrerz	; Berechnen Spur / sektor
;	mvi	a,1
;	jrc	fd$write1
	lda	@dbnk
;fd$write1:
	mov	c,a

; ab hier gemeinsam fuer READ und WRITE
fd$mdma:
	call	?xmove

	lxi	b,1024	; Sektorgroesse fuer Transfer
	call	?move
	xra	a	; DMA-Transfer ready melden
	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 UND WRITE UNTER VERWENDUNG DES PHYSISCHEN FLOPYTREIBERS
;
CALC:
	lxi	h,xpdhe0-fdsd0
	dad	d

	XRÁ	A
	MOÖ	B,Á	ť SIDĹ SELEKÔ AUĆ 0
	STÁ	MSIDAKT
	LDA	@SECT	; 0..9 IST DER BEREICH
	INR	A	; 1..10 STARTSEKTOR DES GEBIETES (1K)
	STA	MSEKAKT
	STA	ASEKAKT	; ANZEIGE SEKTOR ZWISCHENSPEICHERN

	sub	m

;	SUI	6	; PRUEFEN OB VORDERSEITE
	JC	CAL1
	INR	A	; RUECKSEITE SEKTOREN AB 1 (1K)
	STA	MSEKAKT
	MVI	A,1	; SIDE SELECT AUF 1
	STA	MSIDAKT
CAL1:	LDA	@RDRV	; LAUFWERK
	STA	MDRVAKT
	LDA	@TRK	; SPUR
	STA	MTRKAKT

	inx	h
	mov	a,m
	sta	len	; physische Sektorlaenge
	inx	h
	mov	a,m
	sta	stp	; Stepimpulse/Spur

	lxi	h,buffer
	SHLD	ADR
	RET
;

fd$read:		; EINEN SEKTOR LESEN
	CALL	CALC
	CALL	PHREAD	; SEKTOR LESEN
	push	psw
	lda	@dbnk
	ora	a
	jrz	fd$read1
	mov	b,a
	mvi	c,0
	call	?xmove
fd$read1:
	lxi	d,buffer
	lhld	@dma
	lxi	b,1024
	call	?move
	pop	psw
	JR	RETAUS

fd$write:		; SCHREIBEN EINES SEKTORS
	CALL	CALC
	lda	@dbnk
	ora	a
	jrz	fd$write1
	mov	c,a
	mvi	b,0
	call	?xmove
fd$write1:
	lxi	h,buffer
	lded	@dma
	lxi	b,1024
	call	?move
	CALL	PHWRITE
;
RETAUS:
	ora	a
	rz
	mvi	a,1
	ret

	sta	disk$status	; save status for error messages
	ORA	A
	rz		; kein Fehler
; Fehlerauswertung Floppy-Treiber
	lda @ermde ! cpi 0ffh ! jz hard$error
	; Had permanent error, print message like:

	; BIOS Err on d: T-nn, S-nn, <operation> <type>, Retry ?

	call	?pderr	; print message header
	lhld operation$name ! call ?pmsg	; last function

	; then, messages for indicated error

	lda	disk$status	; get status byte from last error
	lxi	h,error$table	; point at table of message addresses
errm1:
	mov e,m ! inx h ! mov d,m ! inx h ; get next message address
	add a ! push psw	; shift left and push residual bits with status
	xchg ! cc ?pmsg ! xchg	; print message, saving table pointer
	pop psw ! jnz errm1	; if any more bits left, continue

;	lxi h,error$msg 
; call ?pmsg	; print "<BEL>, Retry (Y/N) ? "
;	call u$conin$echo	; get operator response
;	cpi 'Y' 
; jz more$retries	; Yes, then retry 10 more times
hard$error:
	MVI	A,1	; Return hard error to BDOS
	RET
;
;
; EINBINDEN PHYSISCHER FLOPPYROUTINEN READ / WRITE
;
PHREAD:
;	mvi	b,19h	; 40 Spur-LW

	MVI	B,39H	; PFTKOM FUER LESEN
	lxi	h,read$msg
	JMP	PHREWR

PHWRITE:
;	mvi	b,1ch	; 40 Spur-LW

	MVI	B,3CH	; PFTKOM FUER SCHREIBEN OHNE VERIFY
	lxi	h,write$msg
PHREWR:
	shld	operation$name
	LDA	MSIDAKT
	ORA	A
	MOV	A,B
	JRZ	PH1
	ORI	80H
PH1:	STA	PFTKOM
;
; ANZEIGE LESE- / SCHREIBVORGANG
;
	BIT	2,A
	MVI	A,'R'
	JRZ	ANZREA
	MVI	A,'W'
ANZREA:	STA	ANZRW
	LDA	@adrv
	ADI	41H
	STA	ANZDRV
	LDA	MTRKAKT
	CALL	HEXASC
	SHLD	ANZTRK
	LDA	ASEKAKT
	CALL	HEXASC
	SHLD	ANZSEK
	LXI	H,ANZEIG
	call	flosta
	lda	@adrv
	cpi	'J'-'A'
	jrnz	nosekv
	lda	msekakt
	adi	40h
	sta	msekakt
nosekv:
	LXI	H,ADR
	LXI	D,PFTADR
	LXI	B,10
	LDIR
	jmp	floppy

;
; UNTERPROGRAMM FUR UMRECHNUNG HEX IN ASCII
;
HEXASC:
	MVI	L,'0'
HEXAS1:	sui	10
	JRC	HEXAS2
	INR	L
	JR	HEXAS1
HEXAS2:	ADI	'0'+10
	MOV	H,A
	RET

	cseg		; Anzeigepuffer im Common fuer MARC-BAB
;
; ANZEIGEPUFFER LESE- / SCHREIBVORGANG
;
ANZEIG:
ANZDRV:	DB	' :'
ANZTRK:	DB	'  /'
ANZSEK:	DB	'   '
ANZRW:	DB	' '

	dseg
;
; RAM - ZELLEN
;
disk$status:
	db	0
operation$name:
	dw	read$msg

read$msg:
	db	', Read',0
write$msg:
	db	', Write',0
;error$msg:
;	db	' Retry (Y/n) ? ',0

	; table of pointer to error message strings
	; first entry is for bit 7 of Biosdskt-Routine

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ş	dâ	§ Drive noô ready,',0
b6$msgş	dâ	§ Disk write protect,',0
;b5$msgş	dâ	' Fault,',0
b5$msg:	db	' Mark not found,',0
b4$msg:	db	' Record not found,',0
b3$msg:	db	' CRC-Error,',0
b2$msg:	db	' Lost data,',0
;b1$msg:	db	' DREQ,',0
b1$msg:	db	' No disk drive,',0
;b0$msg:	db	' Busy,',0
b0$msg:	db	' Track number error,',0

ASEKAKT:
	DB	0	; SEKTOR 1..10 FUER ANZEIGE

; NACHFOLGENDE TABELLE ( BIS STI ) DARF IN IHREM AUFBAU NICHT
; VERAENDERT WERDEN, DA SIE MITTELS LDIR-BEFEHL DEM PHYSISCHEN
; DISKETTENTREIBER UEBERGEBEN WIRD

ADR:	DW	0	; ADRESSE DES BUFFERS FUER PHYSISCHE
			; FLOPPYROUTINE
MDRVAKT:
	DB	0	; DRIVE, DAS GELADEN IST
MTRKAKT:
	DB	0	; TRACK
MSIDAKT:
	DB	0	; SIDE
MSEKAKT:
	DB	0	; SEKTOR
LEN:	DB	3	; PHYSISCHE BLOCKLAENGE
ANZ:	DB	1	; ANZAHL ZU TRANSFERIERENDER SEKTOREN
STP:	DB	1	; ANZAHL STEPIMPULSE PRO SPUR
; fuer 40 Spur-LW:
;STI:	DB	13*10	; SCHRITTZEIT FUER STEP
; FUER 80 SPUR-LW:
STI:	DB	4*10	; SCHRITTZEIT FUER STEP

buffer:	ds	1024	; Floppylese - schreib

	end
