	title	'Module of Loader-BIOS for CP/M 3.0'

	; version 1.0 12.Sept.88

;		  Copyright (C), 1982
;		 Digital Research, Inc
;		     P.O. Box 579
;		Pacific Grove, CA  93950
;
;		and
;
;               Sebastian Simon
;               Haendel-Haus Halle
;               Gr. Nikolaistr. 5-6
;               Halle (Saale)
;               4020
;               Tel.: 24606

    ; CP/M 3 Disk definition macros

	maclib cpm3

    ; Z80 macro library instruction definitions

	maclib z80


	EXTRN	FLOPPY,PFTKOM,PFTADR
	EXTRN	DIOMRK,ITIMEO,LWEXIS,ALWNR,ASPNR,SPNRL

;**************************************************************
; VEREINBARUNGEN
;**************************************************************

MAXDSK	EQU	2

;****************** E/A - VEREINBARUNGEN **********************

CRTPAR	EQU	18H		; CRT-CONTROLLER-PARAMETERREG.
CRTBEF	EQU	19H		; CRT-CONTROLLER-STEUERREGISTER
CRTBWS	EQU	34H		; BWS-ANFANGSADRESSENREGISTER


; Adressen der Floppykarte

; Steuer-PIO
flcoad	equ	04h		;Port A
flcoac	equ	05h
flcobd	equ	06h		;Port B
flcobc	equ	07h

; Daten-PIO
fldaad	equ	00h		;Port A Schreib-Daten
fldaac	equ	01h
fldabd	equ	02h		;Port B Lese-Daten
fldabc	equ	03h

; Select-Latch
flsel	equ	20h	;Bit 7..4: /Select LW3..0; Bit 3..0: /Lock LW 3..0
flmot	equ	21h	;Bit 7..4: /Motor on (von flsel 7..4 durchgeschaltet)


    ; BIOS Jump vector.

		; All BIOS routines are invoked by calling these
		;	entry points.

?boot:	jmp boot	; initial entry on cold start
?wboot:	jmp 0

?const:	jmp 0
?conin:	jmp 0
?cono:	jmp conout	; send console output character
?list:	jmp 0
?auxo:	jmp 0
?auxi:	jmp 0

?home:	jmp home	; set disks to logical home
?sldsk:	jmp seldsk	; select disk drive, return disk parameter info
?sttrk:	jmp settrk	; set disk track
?stsec:	jmp setsec	; set disk sector
?stdma:	jmp setdma	; set disk I/O memory address
?read:	jmp read	; read physical block(s)
?write:	jmp 0

?lists:	jmp 0
?sctrn:	jmp sectrn	; translate logical to physical sector

?conos:	jmp 0
?auxis:	jmp 0
?auxos:	jmp 0
?dvtbl:	jmp 0
?devin:	jmp 0

?drtbl:	jmp 0
?mltio:	jmp 0
?flush:	jmp 0

?mov:	jmp ?move	; block move memory to memory
?tim:	jmp 0
?bnksl:	jmp 0
?stbnk:	jmp 0
?xmov:	jmp 0

	jmp 0		; reserved for future expansion
	jmp 0		; reserved for future expansion
	jmp 0		; reserved for future expansion

	DS	9	; PLATZ SCHAFFEN FUER INTVEKTOR

	; VEREINBARUNGEN FUER INTERRUPTVEKTOR

intvec:			; INTERRUPTTABELLE
IVDSK1:	DS	2
IVDSK2:	DS	2


	; BOOT
	;	Initial entry point for system startup.

BOOT:	DI
	MVI	A,3
	OUT	0AH
	OUT	0BH

;************* SYSTEMGRUNDEINSTELLUNGEN VORNEHMEN *************

; Farbeinstellung
	mvi	a,17h
	out	40h
	rrc
	rrc
	rrc
	rrc
	out	41h
	xra	a
	out	42h

	LXI	H,0F800H	; UND BILDSCHIRM
	LXI	B,800H
BOOT1:	MVI	M,' '
	INX	H
	DCX	B
	MOV	A,B
	ORA	C
	JRNZ	BOOT1
	MVI	B,80H
BOOT2:	MVI	M,0
	INX	H
	DJNZ	BOOT2

;**************** INITIALISIEREN CRT-CONTROLLER ***************

	MVI	A,3EH
	OUT	CRTBWS
	XRA	A		; STOP DISPLAY / RESET
	OUT	CRTBEF
	MVI	A,4FH		; PARAMETER 1
	OUT	CRTPAR
	MVI	A,58H		; PARAMETER 2
	OUT	CRTPAR
	MVI	A,6BH		; PARAMETER 3
	OUT	CRTPAR
	MVI	A,6DH		; PARAMETER 4
	OUT	CRTPAR
	MVI	A,20H		; START DISPLAY
	OUT	CRTBEF

;******************** FLOPPY INITIALISIEREN *******************

;; Port Steuer-B
	lxi	h,diomrk	;; Adressmarken-Interrupt
	shld	ivdsk2
	LXI	H,IVDSK2
	MOV	A,L
	out	flcobc
	mvi	a,0cfh		;; bit E/A
	out	flcobc
	mvi	a,0e3h		;; eeea aaee
	out	flcobc
	mvi	a,00110111b	;; di/oder/high/Maske
	out	flcobc
	mvi	a,11111101b	;; Interrupt bei Marke
	out	flcobc
;; Port Daten-B
	mvi	a,4fh		;; byte-Eingabe
	out	fldabc
;; Port Daten-A
	mvi	a,0fh		;; byte-Ausgabe
	out	fldaac
;; Port Steuer-A
	out	flcoac		;; byte-Ausgabe
	out	flcoad		;; AMF aus
	lxi	h,itimeo
	shld	ivdsk1
	LXI	H,IVDSK1
	MOV	A,L
	out	flcoac		;; Index-Interrupt
	mvi	a,3
	out	flcoac		;; verbieten

;; Select-Latch-Programmierung
	mvi	a,0ffh		;; alle LW ausschalten
	out	flsel
	out	flmot

;; Ermittlung der vorhandenen Laufwerke
	mvi	c,4		;; 4 LAUFWERKE WEGEN VESCH.
	mvi	d,0
	mvi	a,0f7h		;; ohne lock
flka1:	rlc
	out	flsel
	out	flmot
	exaf
	mvi	b,85		;; max 85 mal steppen
flka2:	in	flcobd
	rlc			;; kam Spur0-Signal?
	jrnc	flka4		;; -> ja
	mvi	a,01011111b	;; steppen in Richtung Spur 0
	out	flcoad
	mvi	a,11011111b	;; mit Kopf oben
	out	flcoad
	mvi	h,8		;; 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	flsel
	out	flmot

	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

	LXI	H,INTVEC
	MOV	A,H		; INITIALISIERUNG INTERRUPT
	STAI
	IM2
	EI
	RET

;**************************************************************
; CONSOLAUSGABE
;**************************************************************

CONOUT:	LXI	H,00FFH		; CLEAR CURSOR
	CALL	SETCU3
	LHLD	CURS
	INR	H
	DCR	H
	JRNZ	CON1
	MVI	H,0F8H		; SETZEN KURSOR AUF BILDANFANG
	MVI	M,' '
	SHLD	CURS
CON1:
	PUSH	PSW
	LDA	ESCMER		; WAR ESC-FOLGE ?
	ORA	A
	JRZ	NOESC		; -> NEIN
	DCR	A
	STA	ESCMER
	JRZ	ESC2		; -> 2.BYTE DER ESC-FOLGE
	LXI	H,0F800H	; BEHANDLUNG 1.BYTE DER ESC-FO.
	MOV	A,C		; ALS ZEILENANGABE
	ANI	7FH
	ORA	A
	JRZ	SETCUR
	CPI	18H
	JRC	ESC11
	LXI	H,0F800H
	JR	SETCUR
ESC11:	MOV	B,A
	LXI	D,0050H
ESC12:	DAD	D
	DJNZ	ESC12
	JR	SETCUR
ESC2:	MOV	A,C		; BEHANDLUNG 2.BYTE DER ESC-FO.
	ANI	7FH		; ALS SPALTENANGABE
	CPI	50H
	LXI	D,004FH
	JRNC	ESC22
ESC21:	MOV	E,A
ESC22:	DAD	D
	JR	SETCUR
NOESC:
	MOV	A,C		; AUSWERTUNG STEUERZEICHEN
	CPI	7FH
	JRZ	CHRDEL
	CPI	20H
	JRC	CRTCRTL
CRTZEI:	ANI	7FH
	MOV	M,A		; ZEICHEN AUF BILDSCHIRM
	CALL	CRTCRI
;
SETCUR:
	SHLD	CURS
	CALL	SETCUS
	POP	PSW
	RET
;
SETCUS:
	XRA	A
	LXI	D,0F800H
	DSBC	DE		; SBC HL,DE
	MVI	C,0
	LXI	D,50H
SETCU1:
	DSBC	DE		; SBC HL,DE
	JRC	SETCU2
	INR	A
	JR	SETCU1
SETCU2:
	DAD	D
	MOV	H,A
SETCU3:
	MVI	A,80H		; CURSOR SETZEN
	OUT	CRTBEF
	MOV	A,L		; SPALTE
	OUT	CRTPAR
	MOV	A,H		; ZEILE
	OUT	CRTPAR
	RET

CHRDEL:	CALL	CRTDCH
CRTCRTL:
	CPI	0DH		; STEUERZEICHEN AUSWERTEN
	CZ	CRTCR
	CPI	0AH
	CZ	CRTLF
	CPI	15H
	CZ	CRTCRI
	CPI	08H
	CZ	CRTCLE
	CPI	0CH
	CZ	CRTFF
	CPI	01H
	CZ	CRTHOM
	CPI	14H
	CZ	CRTDRB
	CPI	18H
	CZ	CRTDZE
	CPI	16H
	CZ	CRTDCZ
	CPI	1AH
	CZ	CRTCHO
	CPI	1BH
	CZ	CRTESC
	JMP	SETCUR
CRTDCH:	MVI	M,' '		; DEL
CRTCLE:	DCX	H		; BACKSPACE
	MOV	A,H
	CPI	0F7H
	RNZ
	INX	H
	RET
CRTFF:	LXI	H,0F800H	; FORM FEED
	MVI	M,' '
	LXI	D,0F801H
	LXI	B,077FH
	LDIR
CRTHOM:	LXI	H,0F800H	; HOME POSITION
	RET
CRTLF:	LXI	D,0050H		; LINE FEED
	DAD	D
	MOV	A,H
	CPI	0FFH
	RNZ
	MOV	A,L
	CPI	80H
	RC
	DSBC	DE		; SBC HL,DE
	JR	CRTPO1
CRTCRI:	INX	H		; NAECHSTE KURSORPOSITION
	MOV	A,H		; WENN NOETIG BILD ROLLEN
	CPI	0FFH
	RNZ
	MOV	A,L
	CPI	80H
	RC
	LXI	H,0FF30H
CRTPO1:	PUSH	H
	LXI	B,0730H
	LXI	H,0F850H
	LXI	D,0F800H
	LDIR
	MVI	A,' '
	MVI	B,50H
CRTPO2:	DCX	H
	MOV	M,A
	DJNZ	CRTPO2
	POP	H
	RET
CRTCR:	MOV	B,H		; CARRIAGE RETURN
	MOV	C,L
	LXI	H,0FF80H
	LXI	D,0050H
	ORA	A
CRTCR1:	DSBC	DE		; SBC HL,DE
	PUSH	H
	DSBC	BC		; SBC HL,BC
	POP	H
	RZ
	JRNC	CRTCR1
	RET
CRTESC:	MVI	A,02H		; BEHANDLUNG ESC-FOLGE
	STA	ESCMER		; BEGINNEN
	RET
CRTDRB:	XCHG			; LOESCHEN AB CURSOR BIS
	LXI	H,0FF7FH	; BILDENDE
	DSBC	DE		; SBC HL,DE
	MOV	B,H
	MOV	C,L
CRTDR1:	MOV	H,D
	MOV	L,E
	INX	D
	MVI	M,' '
	LDIR
	LHLD	CURS
	RET
CRTDZE:	CALL	CRTCR		; LOESCHEN KURSORZEILE UND
				; SETZEN KURSOR AN ZEILEN-
				; ANFANG
CRTDCZ:	LXI	D,004FH		; LOESCHEN AB KURSORPOSITION
	DAD	D		; BIS ZEILENENDE
	LDED	CURS		; LD DE,(CURS)
	ORA	A
	DSBC	DE
	MOV	B,H
	MOV	C,L
	JR	CRTDR1
CRTCHO:	LXI	D,0050H		; KURSOR EINE ZEILE HOCH
	DSBC	DE
	MVI	A,0F7H
	CMP	H
	RC
	LHLD	CURS
	RET

CURS:	DW	0F800H		; KURSORMERKER
ESCMER:	DB	0		; ESC - MERKER

;**************************************************************
; UNTERPROGRAMM ZEICHENKETTENAUSGABE
;**************************************************************

PRMMSG:	MOV	A,M
	ORA	A
	RZ
	PUSH	H
	MOV	C,A
	CALL	CONOUT
	POP	H
	INX	H
	JR	PRMMSG

;**************************************************************
; MOVE-FUNKTION
;**************************************************************

?move:
	xchg		; we are passed source in DE and dest in HL
	ldir		; use Z80 block move instruction
	xchg		; need next addresses in same regs
	ret

;**************************************************************
; DISKETTENSTEUERUNG
;**************************************************************

	; SELDSK
	;	Select Disk Drive.  Drive code in <C>.
	;		Invoke login procedure for drive
	;		if this is first select.  Return
	;		address of disk parameter header
	;		in <HL>

seldsk:
	mov a,c ! sta @adrv ! STA @RDRV		; save drive select code
	mov l,c ! mvi h,0 ! dad h		; create index from drive code
	lxi b,@dtbl ! dad b			; get pointer to dispatch table
	mov a,m ! inx h ! mov h,m ! mov l,a	; point at disk descriptor
	ora h ! rz 				; if no entry in table, no disk
	ret


	; HOME
	;	Home selected drive.  Treated as SETTRK(0).

home:
	lxi b,0		; same as set track zero


	; SETTRK
	;	Set Track. Saves track address from <BC> 
	;		in @TRK for further operations.

settrk:
	mov l,c ! mov h,b
	shld @trk
	ret


	; SETSEC
	;	Set Sector.  Saves sector number from <BC>
	;		in @sect for further operations.

setsec:
	mov l,c ! mov h,b
	shld @sect
	ret


	; SETDMA
	;	Set Disk Memory Address.  Saves DMA address
	;		from <BC> in @DMA and sets @DBNK to @CBNK
	;		so that further disk operations take place
	;		in current bank.

setdma:
	mov l,c ! mov h,b
	shld @dma
	ret


	; SECTRN
	;	Sector Translate.  Indexes skew table in <DE>
	;		with sector in <BC>.  Returns physical sector
	;		in <HL>.  If no skew table (<DE>=0) then
	;		returns physical=logical.

sectrn:
	mov l,c ! mov h,b
	mov a,d ! ora e ! rz
	xchg ! dad b ! mov l,m ! mvi h,0
	ret


	; READ
	;	Read physical record from currently selected drive.
	;		Finds address of proper read routine from
	;		extended disk parameter header (XDPH).

read:
	lhld @adrv ! mvi h,0 ! dad h	; get drive code and double it
	lxi d,@dtbl ! dad d		; make address of table entry
	mov a,m ! inx h ! mov h,m ! mov l,a	; fetch table entry
	push h				; save address of table
	lxi d,-8 ! dad d		; point to read routine address
	mov a,m ! inx h ! mov h,m ! mov l,a	; get address of routine
	pop d				; recover address of table
	dcx d ! dcx d			; point to relative drive
	ldax d ! sta @rdrv		; get relative drive code and post it
	inx d ! inx d			; point to DPH again
	pchl				; leap to driver


	; error message components
drive$msg	db	cr,lf,bell,'BIOS Error on ',0
track$msg	db	': T-',0
sector$msg	db	', S-',0


    ; disk communication data items

@adrv	ds	1		; currently selected disk drive
@rdrv	ds	1		; controller relative disk drive
@trk	ds	2		; current track number
@sect	ds	2		; current sector number
@dma	ds	2		; current DMA address


    ; common control characters

cr	equ 13
lf	equ 10
bell	equ 7


;**************************************************************
; VEREINBARUNGEN
;**************************************************************

    ; Extended Disk Parameter Headers (XPDHs)

	DW	0		;dw	fd$write
	dw	fd$read
	DW	0		;dw	fd$login
	DW	0		;dw	fd$init0
	db	0,0		; relative drive zero
fdsd0:
;	dph     TRANS,dpbsd,32,49
	DW	0
	DB	0,0,0,0,0,0,0,0,0
	DB	0
	DW	DPBSD
	DW	CHECK0
	DW	ALLOC0
	DW	DIRBCB
	DW	DTABCB
	DW	0
	DB	0

CHECK0:	DS	32
ALLOC0:	DS	49

	DW	0		;dw	fd$write
	dw	fd$read
	DW	0		;dw	fd$login
	DW	0		;dw	fd$init1
	db	1,0		; relative drive one
fdsd1:
;	dph     TRANS,dpbsd,32,49
	DW	0
	DB	0,0,0,0,0,0,0,0,0
	DB	0
	DW	DPBSD
	DW	CHECK1
	DW	ALLOC1
	DW	DIRBCB
	DW	DTABCB
	DW	0
	DB	0

CHECK1:	DS	32
ALLOC1:	DS	49

DPBSD	DPB	1024,10,80,2048,128,2


    ; Disk I/O routines for standardized BIOS interface


; 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 UNTER VERWENDUNG DES PHYSISCHEN FLOPYTREIBERS
; Write im LOADER nicht benoetigt / nicht implementiert
;
fd$read:		; EINEN SEKTOR LESEN

			» RECHNEÔ @SECÔ IÎ SEKTORBUFFERNÒ UM
	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
	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
	LHLD	@DMA
	SHLD	ADR

; PARAMETER FUER PHYSISCHES LESEN SIND GELADEN !

	CALL	GETTRK	; NEUEN SEKTOR LESEN
	MVI	A,0
	RNC		; KEIN FEHLER
ERRIO:	MVI	A,1	; FEHLER AUFGETRETEN
	RET
;
; BUFFER VERWALTUNG
;
GETTRK:			; TRKAKT,SEKAKT,DRVAKT,SIDE ENTHALTEN
			; NEUE BUFFERADRESSE

; HIER KOPPLUNG PHYSISCHEN TREIBER EINBINDEN
; BUFFER LESEN

	CALL	PHREAD

	JC	ERRX
	XRA	A
	RET

ERRX:	STC
	RET

;
; EINBINDEN PHYSISCHER FLOPPYROUTINE
;
PHREAD:
	MVI	B,39H	; PFTKOM FUER LESEN
	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	MDRVAKT
	ADI	41H
	STA	ANZDRV
	LDA	MTRKAKT
	CALL	HEXASC
	SHLD	ANZTRK
	LDA	ASEKAKT
	CALL	HEXASC
	SHLD	ANZSEK
	LXI	H,ANZEIG
	LXI	D,0FFC7H
	LXI	B,9
	LDIR				; ANZEIGE AUF BILDSCHIRM
	LXI	H,ADR
	LXI	D,PFTADR
	LXI	B,10
	LDIR
	CALL	FLOPPY
	ORA	A
	RZ
	STC
	RET
;
; UNTERPROGRAMM FUR UMRECHNUNG HEX IN ASCII
;
HEXASC:
	MVI	L,'0'
HEXAS1:	CPI	10
	JRC	HEXAS2
	INR	L
	SBI	10
	JR	HEXAS1
HEXAS2:	ADI	'0'
	MOV	H,A
	RET
;
; ANZEIGEPUFFER LESE- / SCHREIBVORGANG
;
ANZEIG:
ANZDRV:	DB	' :'
ANZTRK:	DB	'  /'
ANZSEK:	DB	'   '
ANZRW:	DB	' '
;
; RAM - ZELLEN
;
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
STI:	DB	4*10	; SCHRITTZEIT FUER STEP


DIRBCB:	DB	0FFH,0,0,0,0,0
	DW	0,0,DIRBUF
	DB	0,0,0

DTABCB:	DB	0FFH,0,0,0,0,0
	DW	0,0,DATBUF
	DB	0,0,0

DIRBUF:	DS	1024
DATBUF:	DS	1024

@dtbl	dw fdsd0,fdsd1
	dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0		; drives C-P non-existant

	end
