	title	'Format Handling Routines of CP/M-3 BIOS'
	.z280
	.xlist
	maclib	Z280EQU
	maclib	CPU280
	maclib	OPTIONS
	.list

; 190893 Stefan Nitschke, neue Funktionen 14,15,16  

; 230191 Tilmann Reh
; 930103 TR: RESDMA --> DMA, xLENGTH --> xxLEN, WDMAPB --> WRDMAPB
; 930104 TR: READ1/WRITE1 --> DSKRD1/DSKWR1

	dseg			; Aufruf durch 'System Call', daher gebankt

; USERF wird hier f}r verschiedene spezielle BIOS-Funktionen benutzt.
; ]bergeben wird jeweils eine Adresse in BC und ein Funktionscode in E.
; Alle Funktionen beziehen sich auf das augenblicklich eingeloggte Laufwerk
; (DRIVE,CURDPH,DRVTYP).
; Alle nicht definierten Funktionen bewirken einen ERROR-TRAP.

userf::	ld	a,e		; F-Code
	cp	maxfun
	jr	nc,tohigh	; zu hohe Funktionsnummer: TRAP
	add	a,a
	exts	a		; verdoppelt nach HL
	ldw	hl,(hl++usetab)	; UP-Adresse aus Tabelle holen
	jp	(hl)		; UP anspringen (RET --> SYSRET)

usetab:	defw	vrsion		; 0 : Get BIOS Version Number
	defw	setdel		; 1 : Set Motor-Off Delay
	defw	getdrv		; 2 : Get Selected Drive
	defw	gettyp		; 3 : Get Selected Drive Type
	defw	pseek		; 4 : Set Physical Track Direct (Seek)
	defw	checkd		; 5 : Check Density
	defw	readid		; 6 : Read ID
	defw	readp		; 7 : Read Physical Sector
	defw	writep		; 8 : Write Physical Sector
	defw	format		; 9 : Format a Track
	defw	setfrm		;10 : Set BIOS Parameter Blocks
	defw	getres		;11 : Get Result Address
	defw	check		;12 : Error-Check
	defw	rddiag		;13 : Read Track Diagnostic
	defw	setcache	;14 : Write into cache controll register 
	defw	cpuctrl		;15 ; Lesen der CPU Kontrollreg.
	defw	loadunix	;16 ; Load UZI-System

maxfun	equ	($-usetab) shr 1 ; Anzahl Funktionen

; nicht definierter Aufruf (falsche Funktionsnummer): TRAP-Meldung

tohigh:	pop	hl		; (SYSRET)
	pop	hl		; (MSR)
	pop	hl		; (next instruction)
	push	de		; Funktionscode retten
	ld	hl,trpmsg
	call	pmsg##		; Meldung 'BIOS-TRAP at ' ausgeben
	ldctl	hl,usp		; Stack des aufrufenden Programms
	ldw	hl,(hl)		; ge'pop'te Aufrufadresse
	dec	hl
	dec	hl
	dec	hl		; Aufruf 3 Bytes vor Return-Adresse (bei CALL)
	call	hexadr##	; Adresse ausgeben
	ld	hl,fcode
	call	pmsg##		; Meldung ' Function = ' ausgeben
	pop	hl		; Funktionscode
	ld	h,0
	call	pdec##		; Funktionscode dezimal ausgeben
	jp	wboot##		; Warm-Boot ausf}hren
	
;***********************************************************************
;**                    Get BIOS Version Number                        **
;***********************************************************************
; Versionsnummer wird in HL bin{r }bergeben (H=Main, L=Update).

vrsion:	ld	hl,101h		; BIOS Version 1.01
	ret

;***********************************************************************
;**                      Set Motor-Off Delay                          **
;***********************************************************************
; Motor-Off-Delay wird in 10-ms-Schritten gesetzt. Wert in BC.

setdel:	ld	(delay##),bc	; Delay neu setzen
	ret			; zur}ck (SWI1)

;***********************************************************************
;**                      Get Selected Drive                           **
;***********************************************************************
; das derzeit selektierte Laufwerk wird in HL }bergeben.

getdrv:	ld	a,(drive##)
	exts	a
	ret

;***********************************************************************
;**                          Get Type                                 **
;***********************************************************************
; Laufwerkstyp abfragen (Wert aus NVRAM). Ergebnisse in HL (2..7).

gettyp:	ld	a,(drvtyp##)	; aktueller Laufwerkstyp
	exts	a
	ret

;***********************************************************************
;**               Set Physical Track Direct (Seek)                    **
;***********************************************************************
; Track wird in (B)C }bergeben. Keine Verdopplung bei 48 TPI !

pseek:	push	bc
	call	motonw##	; Motor an
	pop	bc
	ld	a,c
	call	seek##		; SEEK-Routine aus DISKIO
	jp	motoff##

;***********************************************************************
;**                  Check Density (durch ID-Read)                    **
;***********************************************************************
; An der aktuellen Position wird ein Density-Check durchgef}hrt. Danach sind
; DENSE und Takteinstellung g}ltig. Aufruf mit gew{hltem HEAD in C (0/1).
; Bei R}ckkehr: H=FF bei Fehler, sonst H=0. In L wird die festgestellte
; Dichte }bergeben (1=FM,2=MFM,4=HD-MFM).

checkd:	call	gthead		; HEAD aus C auswerten
	call	motonw##
	call	chkden##	; Dichte pr}fen
	push	af
	call	motoff##
	pop	af
	ld	h,-1
	ret	c		; Time-Out
	ret	nz		; Fehler
	ld	hl,4
	ld	a,(ldflag##)
	or	a		; Low-Density?
	ret	z		; HD : RET mit HL=0004
	ld	a,(dense##)
	or	a
	ld	l,2
	ret	nz		; MFM : RET mit HL=0002
	dec	l		; FM : HL=0001
	ret

;***********************************************************************
;**                   Read next ID Information                        **
;***********************************************************************
; Alle Einstellungen werden von vorher (CHECKD!) }bernommen. Head in C.
; 200ms-Z{hler f}r Status-Check wird jedesmal hochgesetzt, damit der Format-
; Manager die richtige Reihenfolge mitbekommt.

readid:	call	gthead		; HEAD aus C auswerten
	ld	(cnt10-1),20	; *** Status-Check-Z{hler auf Maximum
	call	motonw##
	ld	a,(dense##)	; aktuelle Dichte
	call	chkd2##		; damit READ ID
	push	af
	call	motoff##
	pop	af
	ld	hl,-1
	ret	c		; Time-Out:
	ret	nz		; Fehler: RET mit FFFF
	inc	hl
	ret			; OK: RET mit HL=0

;***********************************************************************
;**                   Read Physical Sector                            **
;***********************************************************************
; Eingang: BC zeigt auf Pufferbereich. Darin: 'C H R N' f}r FDC.
;          Es wird grunds{tzlich auf Seite 0 gelesen (Parameter!).
; Ausgang: Puffer mit gelesenen Daten gef}llt.
;          Fehlerfrei wenn HL=0, bei Fehlern HL=FFxx.

readp:	ld	(DMA),bc	; sp{tere Zieladresse
	ld	a,1
	ld	(dbnk),a	; Zielbank
	call	getbuf		; ab BC nach BUFFER kopieren
	call	motonw		; Motor an und warten
	ld	hl,pdrive
	res	2,(hl)		; physikalisch immer Head 0
	ld	hl,(buffer)	; L=Cylinder, H=Head
	ld	(ptrack),hl
	ld	a,l
	call	seek		; Spur in A anfahren
	ld	hl,(buffer+2)
	ld	(psect),hl	; Record und Sector-Shift }bertragen
	ld	a,l
	ld	(eot),a		; EOT = Record
	ld	a,h
	call	setln1		; L{ngen f}r DMA setzen
	ld	hl,(curdph)
	dec	hl
	dec	hl		; Zeiger auf Bit-Flags
	push	(hl)		; alle Flags retten
	push	hl		; Zeiger retten
	res	3,(hl)		; aktuelles Invert-Flag l|schen
	ld	(quiet),-1	; keine Fehlermeldung!
	call	DskRd1		; Sektor lesen
	ld	(quiet),0	; Fehlermeldungen wieder an
	pop	hl		; Zeiger auf Bit-Flags
	pop	(hl)		; Flags restaurieren
	ld	hl,0
	or	a
	ret	z		; ok: HL=0
	dec	hl		; sonst HL=FFFF: Lesefehler
	ret

;***********************************************************************
;**                   Write Physical Sector                           **
;***********************************************************************
; S{mtliche Daten werden von vorhergehendem READ }bernommen, auch DMA-Adresse!
; Ausgang HL: 0 ok, FFFF Schreibfehler, FFFE Protected.

writep:	call	motonw##	; Motor anschalten und warten
	ld	hl,(curdph##)
	dec	hl
	dec	hl		; Zeiger auf Bit-Flags
	push	(hl)		; alle Flags retten
	push	hl		; Zeiger retten
	res	3,(hl)		; aktuelles Invert-Flag l|schen
	call	DskWr1		; Sektor schreiben
	pop	hl		; Zeiger auf Bit-Flags
	pop	(hl)		; Flags restaurieren
	ld	hl,0
	or	a
	ret	z		; ok: HL=0000
	dec	hl
	cp	2		; A=2 : WP ?
	ret	nz		; Schreibfehler: HL=FFFF
	dec	hl
	ret			; WP : HL=FFFE

;***********************************************************************
;**                        Format A Track                             **
;***********************************************************************
; ]bergeben: BC zeigt auf Puffer, dieser enth{lt die folgenden Werte:
; Zeiger auf Indexdaten (CHRN) : Integer;
; Density, Head, SecShift, SecZahl, Gap3, Filler : Byte;
; Ergebnis: FFFF = Schreibfehler, FFFD = NotReady, 0000 = ok
;*** 130191 TR: Density-Angabe wird ignoriert, da BIOS-Parameter schon g}ltig!

format:	call	getbuf		; Parameter in Puffer holen
	ld	hl,(buffer)	; Zeiger auf CHRN-Tabelle
	ld	(DMA),hl	; als DMA-Adresse einsetzen
	ld	(dbnk),1	; DMA-Bank : 1
	iopage	boardp
	call	setclk		; FDC-Takt (High/Low Density) setzen
				; Voreinstellung: Low Density
	ld	hl,(buffer+2)	; L = Density, H = Head
;	bit	2,l
;	call	nz,sethd	; High Density: Taktrate umschalten
	ld	a,0Dh
	dec	l		; --> 0,1,3
	jr	z,form1		; FM : Command = 0D
	ld	a,4Dh		; MFM/HD : Command = 4D
form1:	ld	(buffer+2),a	; als Befehl speichern
	ld	a,h		; Head 0..1
	rlca
	rlca			; --> in Bit 2
	or	a,(drive)	; Laufwerk dazu
	ld	(buffer+3),a	; als US/HS speichern
	ld	a,(buffer+5)	; Sectors per Track
	multu	a,4		; HL = Anzahl Bytes f}r DMA-Transfer
	ld	(WrLen),hl	; in DMA-PB einsetzen
	call	motonw		; Motor an und warten
	ldw	(retry),$+6	; Einsprung f}r Wiederholungen
	ld	bc,603h		; maximal 3 Versuche, 6 Byte Befehlsl{nge
formlp:	push	bc
	ldw	(cmdadr),buffer+2 ; Befehlszeiger kurzfristig hier
	ld	de,WrDmaPB
	call	dskio		; DMA und FDC anwerfen
	ldw	(cmdadr),clist	; Befehle wieder aus CLIST (evtl. in TIMERR!)
	pop	bc
	call	c,timerr	; Time-Out: User fragen
	jr	c,formxe	; Abbruch: Ende mit HL=FFFF
	call	errchk		; Fehler aufgetreten ?
	ld	hl,0
	jr	z,formex	; nein: Ende mit 0000 als Ergebnis
	dec	c
	jr	nz,formlp	; sonst max. 3 mal wiederholen
formxe:	ld	hl,-1		; Fehler: Return mit FFFF
formex:	exx			; Ergebnis retten
	call	motoff		; Motor aus
;	iopage	boardp
;	call	setclk		; Takt wieder entspr. Laufwerk setzen
	ld	hl,(RdLen)
	ld	(WrLen),hl	; DMA-L{nge restaurieren
	exx			; Ergebniscode in HL
	ret

;***********************************************************************
;**                   Set BIOS Parameter Blocks                       **
;***********************************************************************
; Parameterblocks des derzeit selektierten Laufwerks werden beschrieben.

setfrm:	call	getbuf		; (BC) nach BUFFER kopieren
	jp	actdpb		; Parameterblock setzen, RET

;***********************************************************************
;**                        Get Result Address                         **
;***********************************************************************
; Adresse von 'CHRN' in RESULT wird in HL }bergeben.

getres:	ld	hl,result##+3
	ret

;***********************************************************************
;**                         Error-Check                               **
;***********************************************************************
; RESULT wird mit entspr. Masken verkn}pft. HL=0 ok, FFFF nicht ok.

check:	call	errchk##
	ld	hl,0
	ret	z		; ok: RET mit 0000
	dec	hl
	ret			; sonst FFFF

;***********************************************************************
;**                     Read Track Diagnostic                         **
;***********************************************************************
; Lesen einer ganzen Spur (Daten werden verworfen). FDC-Takt mu~ stimmen.
; Eingang: BC zeigt auf Pufferbereich. Darin: 'C H R N' f}r FDC (1.Sektor)
;          Daran anschlie~end Gesamtl{nge (Word), Kopf (Bit) und EOT (Byte).
; Ausgang: Flag in HL: 0=fehlerfrei, bei Fehlern HL=FFxx.

rddiag:	call	getbuf		; Buffer in System-Bank kopieren
	ld	hl,(buffer)
	ld	(ptrack),hl	; C H setzen
	ld	hl,(buffer+2)
	ld	(psect),hl	; R N setzen
	ld	hl,(buffer+4)
	ld	(geslen),hl	; Gesamtl{nge in Byte
	ld	bc,(buffer+6)	; C=Kopf, B=EOT
	call	gthead		; Kopf in pdrive einsetzen
	ld	a,b
	ld	(eot),a		; letzten Sektor setzen
	ld	hl,dmapb
	call	dmaset		; DMA aktivieren
	ld	a,(dense)
	or	2		; FDC Command: READ DIAGNOSTIC (READ TRACK)
	ld	(clist),a
	ld	b,9
	call	intcom		; FDC starten
	ld	hl,-1
	ret	c		; Time-Out: Ende mit HL=FFFF
	ld	a,(result)	; FDC Status 0
	and	10010000b	; Normal und Abnormal Termination sind ok!
	ret	nz		; Invalid Command oder Equipment Check (Home)
	ld	a,(result+1)	; FDC Status 1
	and	00110011b	; DE,OR,NW,MA sind Fehler (EN,ND ignorieren)
	ret	nz
	ld	a,(result+2)	; FDC Status 2
	and	01110111b	; CM,DD,WC,SN,BC,MD sind Fehler (SH ist ok)
	inc	hl	
	ret			; ok: HL=0

dmapb:	defb	dal0		  ; DMA 0
	defw	diadum
	defb	81h		  ; Dest: Dummy-Byte in System-Bank
	defb	fdcdack,0,boardp  ; Src FDCDACK
geslen: defs	2		  ; Gesamt-L{nge wird eingesetzt
	defw	1110000010000100b ; DMA 0 burst enable, Read, noInc
diadum:	defs	1

; F}r einige Funktionen gemeinsam:
; (BC) nach BUFFER kopieren (128 Byte).

getbuf:	ld	d,b
	ld	e,c		; Quellenadresse nach DE
	ld	bc,1		; DestBank 0, SrcBank 1
	call	xmove##		; Banks setzen
	ld	hl,buffer##	; Zieladresse
	ld	bc,128		; L{nge des Parameterblocks
	jp	move##		; Parameterblock in Buffer }bertragen

; Head aus C nach PDRIVE einsetzen.

gthead:	ld	hl,pdrive##
	res	2,(hl)		; Head vorl{ufig 0
	bit	0,c
	ret	z
	set	2,(hl)		; MSB gesetzt : Head 1
	ret

; Cache Control register setzen. (b)c = Mode
setcache:
	push	bc
	pop	hl
	ld	bc,12h		; Points to cache control register
	ldctl	(c),hl
	ret

; CPU Kontrollreg lesen
cpuctrl:
	ldctl	hl,(c)
	ret


; Load UNIX_System   SN

unix_len   equ   7a00h          ; laenge/2 des unix-systems
unix_start equ   0000h

loadunix:
        iopage 0feh
        in     a,(0e1h)
        and    7fh
        out    (0e1h),a       ; counter 0 stoppen !!   

        di  
        ld     hl,ld_unix
        jp   dmasetunix      ; speicher copieren und unix starten  
	
trpmsg:	defm	bel,cr,lf,'BIOS-TRAP at ',0
fcode:	defm	', Function = ',0


;***********************************************************************
;**         DMA-Ansteuerung zum laden von UNIX                        **
;***********************************************************************

; DMA-Register mit den Werten ab (HL) laden. Parameterblock:
; 8 Bit DMA-Adr, 24 Bit Dest, 24 Bit Src, 16 Bit Length, 16 Bit Control.

     cseg  ; this is im comm memory

dmasetunix:
        ld	b,l
	iopage	dmap
	ld	l,b
	ld	c,(hl)		; Adresse DMA-Register
	inc	hl
	outiw			; DAL
	inc	c
	dec	hl
	outiw			; DAH
	inc	c
	outiw			; SAL
	inc	c
	dec	hl
	outiw			; SAH
	inc	c
	outiw			; Length
	inc	c
	outiw			; Descriptor

        iopage busp
	jp     unix_start       ; start unix_system


     dseg

; DMA-Parameterblock f}r UNIX-Load
ld_unix:
	defb	dal3		; DMA 3
	defw	00000h
	defb	81h		; Dest 810000h -> IVT at 810000h phys.
	defw	0200h            
	defb	80h		; Src 800200 means logical 200h of TPA
	defw	unix_len	; Length of unix-system
	defw	1000001100000000b ; descriptor -> 16-Bit Transfer mem -> mem

	end
