;********************************************************
;*							*
;*	DISK I/O SUBROUTINES FOR CP/M CBIOS		*
;*							*
;********************************************************
;
;
;	SUBROUTINES FOR RESTORE, SET-TRACK, SET-SECTOR AND
;	SET-DMA BIOS ENTRY POINTS. THESE ONLY STORE THEIR
;	RESPECTIVE PARAMETERS AND THEN EXIT WITHOUT DOING
;	ANY ACTUAL DISK I/O OPERATIONS.
;
;
HOME:
	LD	BC,0

SETTRACK:
	LD	(TRACK),BC
	RET
;
;
;
;
SETSECT:
	LD	HL,SECTOR
	LD	(HL),C
	RET
;
;
;
;
SETDMA:
	LD	(POINTR),BC
	RET
;
;
;
;
SECTRAN:
	LD	H,B
	LD	L,C		;GET LOGICAL SECTOR# INTO HL FROM BC
	LD	A,D
	OR	E		;CHECK FOR XLT POINTER IN DE=0
	JR	Z,STRAN2	;JUMP IF NO TRANSLATE TABLE USED

	ADD	HL,DE		;ELSE INDEX INTO TABLE BY SECTOR#
	LD	L,(HL)
	LD	H,0
	RET			;RETURN PHYSICAL SECTOR# FROM TABLE
;
STRAN2:	INC	HL		;MAKE SECTOR NUMBERS START AT 1
	RET

	PAGE
;
;****************************************************************
;								*
;	MAGIC SELDISK ROUTINE WITH AUTO DISK PARAMETER SELECT	*
;								*
;****************************************************************
;
PORT0	EQU	0C8H		;DISK CONTROL BIT LATCH
PORT1	EQU	0D9H		;DISK TYPE BIT LATCH
SEL5	EQU	0		;51/4 SELECT BIT
SIDSEL	EQU	1		;BIT# OF SIDE SELECT BIT
SMC1	EQU	2
SMC2	EQU	3
DDEN	EQU	4
;
ON	EQU	1000B
OFF	EQU	0000B
;
;
SELDISK:
	LD	HL,0		;PREP TO CHECK FOR MAX DISK#
	LD	A,C
	CP	NFLOPPY+WINCH
	RET	NC		;ERROR (HL=0) IF DISK# TOO BIG

	LD	(DISK),A
	INC	A
	LD	BC,DPHSIZ
	LD	HL,DPHTAB-DPHSIZ
SDSK2:	ADD	HL,BC
	DEC	A
	JR	NZ,SDSK2
	LD	(DPHPTR),HL	;STORE POINTER TO DISK'S DPH ENTRY
	BIT	0,E		;TEST LOG-ON VECTOR BIT FOR DRIVE

	IF	MIXED
	JR	Z,SDK2A		;EXIT IF DRIVE IS LOGGED-ON
SDK2C:	
	CALL	CKTYPE
	JP	C,D8SEL		;RESET SELECTION TO 8 INCH
	JP	D5SEL		;MUST BE 5 INCH

SDK2A:
	ELSE
	RET	NZ
	ENDIF

	PUSH	HL
	POP	IX
	BIT	0,(IX+FLAGS)	;TEST DRIVE PRE-SELECTED FLAG

	IF	MIXED
	JR	NZ,SDK2C	;EXIT IF DRIVE FORMAT ALREADY KNOWN

	ELSE
	RET	NZ		;EXIT IF DRIVE FORMAT ALREADY KNOWN
	ENDIF

	CALL	FLUSH		;FINISH ANY DEFERRED DISK OPERATIONS

	IF	MIXED
	CALL	CKTYPE		;CHECK FOR DRIVE TYPE
	LD	A,R5ESERV	;PRESELECT 5 INCH
	JR	NC,SDSK3
	LD	A,R8ESERV	;SELECT 8 INCH
SDSK3:
	ELSE
	LD	A,RESERV
	ENDIF
	LD	(TRACK),A	;SEEK DIRECTORY TRACK FOR FORMAT CHECK
;
;
PARAMS:
	IF	WINCH
	LD	HL,WINSTUFF
	LD	(PRMPTR),HL	;SELECT WINCHESTER DISK PARAMS
	LD	A,(DISK)
	CP	NFLOPPY
	JP	Z,PARM10	;SKIP FLOPPY FORMAT CHECK ON HARD DISK
	ENDIF
	XOR	A		;SET SECTOR# TO ZERO TO INDICATE
	LD	(HSTSEC),A	; EXPLORATORY READ OPERATION
PARM1:	LD	A,SIDSEL+OFF
	OUT	(PORT0),A	;MAKE SURE SIDE #0 OF DISK IS SELECTED
	LD	A,(DISK)
	LD	(HSTDSK),A	;STORE UNIT# IN CASE OF ERROR
	LD	C,A

	IF	MIXED
	CALL	CKTYPE
	CALL	C,D8SEL
	CALL	NC,D5SEL
	ENDIF
	CALL	MONITR+27	;SELECT NEW DISK DRIVE
	JR	NZ,PARM2
	LD	A,(TRACK)
	LD	(HSTTRK),A	;STORE TRACK# IN CASE OF ERROR
	LD	C,A
	CALL	MONITR+33	;SEEK SPECIFIED TEST TRACK
	JR	NZ,PARM2
	LD	HL,IDBUFF
	CALL	MONITR+42	;READ AN ID MARK FROM TEST TRACK
	JR	Z,PARM3

PARM2:	CALL	REPORT		;DISPLAY ERROR AND ALLOW RECOVERY
	JR	Z,PARM1		;TRY AGAIN IF NOT ABORTED
	LD	HL,0
	RET			;ELSE RETURN PERM SELECT ERROR
;
;	ARRIVE HERE AFTER SUCCESSFULLY READING AN ID RECORD
;
PARM3:
	IF	MIXED
	CALL	CKTYPE
	LD	HL,S5DSTUFF	;PRESELECT 5 INCH
	JR	NC,PARM3B
	LD	HL,S8DSTUFF	;SELECT 8 INCH
PARM3B:
	ELSE
	LD	HL,SDSTUFF
	ENDIF
	LD	(PRMPTR),HL	;FIRST SELECT SINGLE DENSITY PARAMETERS
	LD	A,(IDBUFF+6)
	BIT	0,A		;TEST DENSITY BYTE RETURNED BY READID
	JP	Z,PARM10	;JUMP IF SINGLE DENSITY

	IF	MIXED
	CALL	CKTYPE
	LD	HL,D5DSTUFF	;PRESELECT 5 INCH
	JR	NC,PARM3C
	LD	HL,D8DSTUFF	;SELECT 8 INCH
PARM3C:
	ELSE
	LD	HL,DDSTUFF
	ENDIF
	LD	(PRMPTR),HL	;USE DUAL DENSITY DISK PARAMETERS
	IF	MIXED
	CALL	CKTYPE
	LD	HL,N5TRAKS-R5ESERV  ;PRESELECT 5 INCH
	JR	NC,PARM3D
	LD	HL,N8TRAKS-R8ESERV
PARM3D:
	ELSE
	LD	HL,NTRAKS-RESERV
	ENDIF
	PUSH	HL		;PUT TRACKS-PER-DISK PARAM ONTO STACK
	IF	DOUBLE
	LD	A,SIDSEL+ON
	OUT	(PORT0),A	;SELECT TOP SIDE OF DISK
	LD	HL,IDTOP
	CALL	MONITR+42	;ELSE READ AN ID MARK FROM TOP SIDE
	JR	NZ,PARM3A	;JUMP IF NOT FORMATTED ON SECOND SIDE
	LD	HL,IDBUFF
	LD	DE,IDTOP	;ELSE COMPARE ID FIELDS TO EACH OTHER
	CALL	EXOR1
	JR	NZ,PARM3A	;JUMP IF TRACK NUMBERS NOT IDENTICAL
	CALL	EXOR1
	CP	1
	JR	NZ,PARM3A	;JUMP IF SIDE NUMBERS NOT COMPLIMENTARY
	CALL	EXOR2
	JR	NZ,PARM3A	;JUMP IF SECTOR LENGTHS NOT IDENTICAL
	CALL	EXOR3
	JR	NZ,PARM3A	;JUMP IF DENSITIES NOT IDENTICAL

	IF	MIXED
	CALL	CKTYPE
	LD	HL,2*N5TRAKS-R5ESERV
	JR	NC,PARM3E
	LD	HL,2*N8TRAKS-R8ESERV
PARM3E:
	ELSE
	LD	HL,2*NTRAKS-RESERV
	ENDIF
	EX	(SP),HL		;REPLACE DOUBLE SIDED #TRACKS ON STACK
PARM3A:	LD	A,SIDSEL+OFF
	OUT	(PORT0),A	;SWITCH BACK TO REGULAR SIDE OF DISK
	ENDIF
	LD	A,(IDBUFF+3)	;GET SECTOR LENGTH BYTE FROM ID RECORD
	AND	00000011B

	IF	MIXED
	LD	H,A		;SAVE 'A'
	CALL	CKTYPE
	LD	A,H
	JR	NC,PARM3F
	LD	(D8DSTUFF+17),A	;STORE AS DEBLOCK MASK IN 'DDSTUFF'
	JR	PARM3G
PARM3F:
	LD	(D5DSTUFF+17),A
PARM3G:
	ELSE
	LD	(DDSTUFF+17),A	;STORE AS DEBLOCK MASK IN 'DDSTUFF'
	ENDIF
	LD	H,0
	LD	L,A
	ADD	HL,HL
	ADD	HL,HL		;MULTIPLY LENGTH CODE BY 4 FOR INDEXING

	IF	MIXED
	PUSH	AF
	CALL	CKTYPE
	LD	BC,F5RMTAB
	LD	DE,D5DSTUFF+18
	JR	NC,PARM3H
	LD	BC,F8RMTAB
	LD	DE,D8DSTUFF+18
PARM3H:
	POP	AF
	ELSE
	LD	BC,FRMTAB
	LD	DE,DDSTUFF+18
	ENDIF
	ADD	HL,BC		;ADD BASE ADDRESS OF FORMAT POOP TABLE
	LD	BC,3
	LDIR			;STORE FORMAT PARAMS IN 'DDSTUFF'

	INC	A
	LD	B,A		;B=SECTOR LENGTH CODE+1 (RANGE 1..4)
	LD	A,(IDBUFF+1)	;GET SIDE# BYTE FROM ID RECORD
	SRL	A		;SHIFT OUT SIDE# BIT IN LSB
	JR	NZ,PARM5	;JUMP IF UPPER 7 BITS ARE NON-ZERO
	LD	A,(HL)		;ELSE USE STANDARD VALUE FOR 'SPT'
	JR	PARM6		; FOUND IN PARAMETER TABLE
;
PARM4:	ADD	A,A		;MULTIPLY PHYSICAL SPT BY 2,4 OR 8 TO
PARM5:	DJNZ	PARM4		; TO GET EQUIVALENT 128 BYTE SECTORS
PARM6:
	IF	MIXED
	LD	H,A		;SAVE 'A'
	CALL	CKTYPE
	LD	A,H
	JR	NC,PARM6A
	LD	(D8DSTUFF+2),A	;STORE LOGICAL SPT CONST IN 'DDSTUFF'
PARM6A:
	LD	(D5DSTUFF+2),A
	ELSE
	LD	(DDSTUFF+2),A	;STORE LOGICAL SPT CONST IN 'DDSTUFF'
	ENDIF

	POP	DE		;POP TRACKS-PER-DISK PARAM OFF STACK
	LD	HL,0
	LD	B,A		;PREPARE TO COMPUTE 'DRM' VALUE FOR DPB
PARM7:	ADD	HL,DE
	DJNZ	PARM7		;GET PRODUCT OF SPT*(NTRAKS-RESERV)

	IF	MIXED
	CALL	CKTYPE
	LD	A,(D5DSTUFF+4)
	JR	NC,PARM7A
	LD	A,(D8DSTUFF+4)
PARM7A:
	ELSE
	LD	A,(DDSTUFF+4)
	ENDIF

	LD	B,A
PARM8:	SRL	H		;DIVIDE TOTAL SECTORS BY 'BSH' TO GET
	RR	L		; NUMBER OF BLOCKS ON DISK
	DJNZ	PARM8
	DEC	HL		;RESULT LESS 1 IS 'DSM' VALUE FOR DPB

	IF	MIXED
	CALL	CKTYPE
	JR	NC,PARM8A
	LD	(D8DSTUFF+7),HL
	LD	A,(D8DSTUFF+5)	;GET BLOCK MASK FROM DPB
	JR	PARM8B
PARM8A:
	LD	(D5DSTUFF+7),HL
	LD	A,(D5DSTUFF+5)
PARM8B:
	ELSE
	LD	(DDSTUFF+7),HL
	LD	A,(DDSTUFF+5)	;GET BLOCK MASK FROM DPB
	ENDIF

	SRL	A
	SRL	A
	SRL	A		;SHIFT RIGHT 3 TIMES GIVES EXTENT MASK
	INC	H
	DEC	H		;TEST IF 'DSM' IS > 255
	JR	Z,PARM9
	SRL	A
PARM9:
	IF	MIXED
	LD	H,A
	CALL	CKTYPE
	LD	A,H
	JR	NC,PARM9A
	LD	(D8DSTUFF+6),A	;STORE VALUE FOR 'EXM'
	JR	PARM9B
PARM9A:
	LD	(D5DSTUFF+6),A
PARM9B:
	ELSE
	LD	(DDSTUFF+6),A	;STORE VALUE FOR 'EXM'
	ENDIF

PARM10:	LD	HL,(PRMPTR)
	LD	DE,(DPHPTR)
	PUSH	DE
	PUSH	DE
	PUSH	DE		;SAVE 3 COPIES OF POINTER TO DISK POOP
	LD	BC,2
	LDIR			;COPY 'XLT' ADDRESS TO START OF DPH
	EX	DE,HL
	LD	BC,14
	ADD	HL,BC		;POINT TO REST OF DPB STUFF NOW
	EX	DE,HL
	LD	BC,15+4
	LDIR			;COPY DPB AND DEBLOCK PARAMETERS
	POP	IX		;POINT IX TO BASE OF DISK STORAGE AREAS
	LD	HL,DIRBUF	;GET ADDRESS OF DIRECTORY BUFFER
	LD	(IX+8),L
	LD	(IX+9),H	;STORE IN 'DIR' POINTER SLOT
	POP	HL
	LD	DE,16
	ADD	HL,DE		;COMPUTE ADDRESS OF DISK PARM BLOCK
	LD	(IX+10),L
	LD	(IX+11),H	;STORE IN 'DPB' POINTER SLOT
	LD	DE,15+4+1
	ADD	HL,DE		;COMPUTE ADDRESS OF CHECK VECTOR
	LD	(IX+12),L
	LD	(IX+13),H	;STORE IN 'CKV' POINTER SLOT
	LD	E,(IX+16+11)
	LD	D,(IX+16+12)	;LOAD DE WITH CHECK VECTOR LENGTH
	ADD	HL,DE		;COMPUTE ADDRESS OF ALLOCATION VECTOR
	LD	(IX+14),L
	LD	(IX+15),H	;STORE IN 'ALV' POINTER SLOT
	POP	HL
	XOR	A		;A=0 TO INDICATE PARAMS FOUND OK
	RET			;RETURN WITH DPH POINTER IN HL
;
;
;
EXOR3:	INC	HL
	INC	DE
EXOR2:	INC	HL
	INC	DE
EXOR1:	LD	A,(DE)
	XOR	(HL)		;COMPARE ID FIELD BYTES @HL AND @DE
	INC	HL
	INC	DE
	RET

	IF	MIXED
;
SETDENS:
	PUSH	HL
	PUSH	BC		;SAVE 'BC'
	LD	A,(DSKTYP)
	AND	00000011B
	LD	B,0
	LD	C,A
	LD	HL,SMCTAB
	ADD	HL,BC		;INDEX INTO SMC DATA SEPARATOR CONTROL
	ADD	HL,BC		; BYTE TABLE FOR NEW DENSITY SETTING
	ADD	HL,BC
	LD	B,3
	LD	C,PORT0
	OTIR			;OUTPUT 3 BYTES TO SET DISK DENSITY
	POP	BC
	POP	HL
	RET

SMCTAB:	DEFB	SMC1+ON		;8 INCH SINGLE DENSITY
	DEFB	SMC2+OFF
	DEFB	DDEN+ON
	DEFB	SMC1+OFF	;8 INCH DOUBLE DENSITY
	DEFB	SMC2+OFF
	DEFB	DDEN+OFF
	DEFB	SMC1+OFF	;5 INCH SINGLE DENSITY
	DEFB	SMC2+ON
	DEFB	DDEN+ON
	DEFB	SMC1+ON		;5 INCH DOUBLE DENSITY
	DEFB	SMC2+OFF
	DEFB	DDEN+OFF
;
;
D8SEL:
	PUSH	AF		;SAVE FLAGS
	LD	A,(DSKTYP)
	RES	1,A		;SET TYPE TO 8 INCH
	LD	(DSKTYP),A
	LD	A,(SPEED8)	;8 INCH DRIVE SPEED
	LD	(SPEED),A
	LD	A,1
	LD	(NREVS),A	;1 REVS BEFORE READY
	LD	A,6*20		;20 SEC STOP DELAY
	LD	(NSTOP),A
	LD	A,SEL5+OFF	;SELECT 8 INCH
D8SELA:
	OUT	(PORT1),A
	LD	A,SIDSEL+OFF	;PRESELECT SIDE 0
	OUT	(PORT0),A
	CALL	SETDENS		;SET SMC DATA SEPARATOR
	POP	AF
	RET

D5SEL:
	PUSH	AF
	LD	A,(DSKTYP)
	SET	1,A		;SET TYPE TO 51/4 INCH
	LD	(DSKTYP),A
	LD	A,(SPEED5)	;5 1/4 INCH DRIVE SPEED
	LD	(SPEED),A
	LD	A,3
	LD	(NREVS),A	;3 REVS BEFORE READY
	LD	A,5*20		;20 SEC STOP DELAY
	LD	(NSTOP),A
	LD	A,SEL5+ON	;SELECT 5 1/4 INCH
	JR	D8SELA
;
	ENDIF
	PAGE
;
	IF	EIGHT
;
;	DISK PARAMS FOR STANDARD SINGLE DENSITY FORMAT
;	26 SECTORS / 128 BYTES
;
SDSTUFF:
	DEFW	XLTAB		;1-IN-6 SECTOR SKEW TABLE

	DEFW	NSECTS		;SECTORS PER TRACK
	DEFB	3		;BLOCK SHIFT
	DEFB	00000111B	;BLOCK MASK
	DEFB	00000000B	;EXTENT MASK
	DEFW	242		;MAX BLOCK#
	DEFW	63		;MAX DIRECTORY ENTRY#
	DEFB	11000000B	;ALLOCATION MASK MSB
	DEFB	00000000B	;'             ' LSB
	DEFW	16		;CHECK SIZE
	DEFW	RESERV		;RESERVED TRACKS

	DEFB	0		;DEBLOCK SHIFT COUNT
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;BYTES PER SECTOR
;
;
;	8 INCH STANDARD SECTOR TRANSLATE TABLE
;
XLTAB:	DEFB	01,07,13,19,25
	DEFB	05,11,17,23
	DEFB	03,09,15,21
	DEFB	02,08,14,20,26
	DEFB	06,12,18,24
	DEFB	04,10,16,22
;
;
;	SECTOR DEBLOCK PARAMS FOR 8 INCH DOUBLE DENSITY DISKS
;
FRMTAB:
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;PHYSICAL SECTOR LENGTH
	DEFB	52		;LOGICAL SECTORS PER TRACK

	DEFB	00000001B
	DEFW	256
	DEFB	26*2

	DEFB	00000011B
	DEFW	512
	DEFB	15*4

	DEFB	00000111B
	DEFW	1024
	DEFB	8*8

	ENDIF
;
;
	IF	FIVE
;
;	DISK PARAMS FOR STANDARD SINGLE DENSITY FORMAT
;	18 SECTORS / 128 BYTES
;
SDSTUFF:
	DEFW	XLTAB		;1-IN-5 SECTOR SKEW TABLE

	DEFW	NSECTS		;SECTORS PER TRACK
	DEFB	3		;BLOCK SHIFT
	DEFB	00000111B	;BLOCK MASK
	DEFB	00000000B	;EXTENT MASK
	DEFW	MBLK		;MAX BLOCK#
	DEFW	63		;MAX DIRECTORY ENTRY#
	DEFB	11000000B	;ALLOCATION MASK MSB
	DEFB	00000000B	;'	       ' LSB
	DEFW	16		;CHECK SIZE
	DEFW	RESERV		;RESERVED TRACKS

	DEFB	0		;DEBLOCK SHIFT COUNT
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;BYTES PER SECTOR
;
;
;	5 INCH SECTOR TRANSLATE TABLE (SAME AS XEROX/CROMEMCO/OSBORNE)
;
XLTAB:
	DEFB	01,06,11,16
	DEFB	03,08,13,18
	DEFB	05,10,15
	DEFB	02,07,12,17
	DEFB	04,09,14
;
;
;	SECTOR DEBLOCK PARAMS FOR 5 INCH DOUBLE DENSITY DISKS
;
FRMTAB:
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;PHYSICAL SECTOR LENGTH
	DEFB	28		;LOGICAL SECTORS PER TRACK

	DEFB	00000001B
	DEFW	256
	DEFB	18*2

	DEFB	00000011B
	DEFW	512
	DEFB	9*4

	DEFB	00000111B
	DEFW	1024
	DEFB	5*8

	ENDIF
;
	IFE	MIXED;
;	BASIC DISK PARAMS FOR DOUBLE DENSITY FORMATS
;
	DPBGEN	BLS,DIRSIZ	;GENERATE BSH/BLM/DIRMSK CONSTS
;
DDSTUFF:
	DEFW	0		;NO SECTOR SKEW TABLE

	DEFW	0		;SECTORS PER TRACK (DUMMY)
	DEFB	BSHFT		;BLOCK SHIFT
	DEFB	BMASK		;BLOCK MASK
	DEFB	0		;EXTENT MASK (DUMMY)
	DEFW	0		;MAX BLOCK# (DUMMY)
	DEFW	DIRSIZ-1	;MAX DIRECTORY ENTRY#
	DEFB	HIGH DIRMSK	;ALLOCATION MASK MSB
	DEFB	LOW DIRMSK	;ALLOCATION MASK LSB
	DEFW	DIRSIZ/4	;CHECK VECTOR SIZE
	DEFW	RESERV		;RESERVED TRACKS

	DEFB	0		;DEBLOCK SHIFT COUNT (DUMMY)
	DEFB	0		;DEBLOCK MASK (DUMMY)
	DEFW	0		;BYTES PER SECTOR (DUMMY)

	ENDIF

	PAGE
	IF	MIXED
;
;	DISK PARAMS FOR STANDARD SINGLE DENSITY FORMAT
;	26 SECTORS / 128 BYTES
;
S8DSTUFF:
	DEFW	X8LTAB		;1-IN-6 SECTOR SKEW TABLE

	DEFW	N8SECTS		;SECTORS PER TRACK
	DEFB	3		;BLOCK SHIFT
	DEFB	00000111B	;BLOCK MASK
	DEFB	00000000B	;EXTENT MASK
	DEFW	242		;MAX BLOCK#
	DEFW	63		;MAX DIRECTORY ENTRY#
	DEFB	11000000B	;ALLOCATION MASK MSB
	DEFB	00000000B	;'             ' LSB
	DEFW	16		;CHECK SIZE
	DEFW	R8ESERV		;RESERVED TRACKS

	DEFB	0		;DEBLOCK SHIFT COUNT
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;BYTES PER SECTOR
;
;
;	8 INCH STANDARD SECTOR TRANSLATE TABLE
;
X8LTAB:	DEFB	01,07,13,19,25
	DEFB	05,11,17,23
	DEFB	03,09,15,21
	DEFB	02,08,14,20,26
	DEFB	06,12,18,24
	DEFB	04,10,16,22
;
;
;	SECTOR DEBLOCK PARAMS FOR 8 INCH DOUBLE DENSITY DISKS
;
F8RMTAB:
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;PHYSICAL SECTOR LENGTH
	DEFB	52		;LOGICAL SECTORS PER TRACK

	DEFB	00000001B
	DEFW	256
	DEFB	26*2

	DEFB	00000011B
	DEFW	512
	DEFB	15*4

	DEFB	00000111B
	DEFW	1024
	DEFB	8*8

;
;	DISK PARAMS FOR STANDARD SINGLE DENSITY FORMAT
;	18 SECTORS / 128 BYTES
;
S5DSTUFF:
	DEFW	X5LTAB		;1-IN-5 SECTOR SKEW TABLE

	DEFW	N5SECTS		;SECTORS PER TRACK
	DEFB	3		;BLOCK SHIFT
	DEFB	00000111B	;BLOCK MASK
	DEFB	00000000B	;EXTENT MASK
	DEFW	M5BLK		;MAX BLOCK#
	DEFW	63		;MAX DIRECTORY ENTRY#
	DEFB	11000000B	;ALLOCATION MASK MSB
	DEFB	00000000B	;'	       ' LSB
	DEFW	16		;CHECK SIZE
	DEFW	R5ESERV		;RESERVED TRACKS

	DEFB	0		;DEBLOCK SHIFT COUNT
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;BYTES PER SECTOR
;
;
;	5 INCH SECTOR TRANSLATE TABLE (SAME AS XEROX/CROMEMCO/OSBORNE)
;
X5LTAB:
	DEFB	01,06,11,16
	DEFB	03,08,13,18
	DEFB	05,10,15
	DEFB	02,07,12,17
	DEFB	04,09,14
;
;
;	SECTOR DEBLOCK PARAMS FOR 5 INCH DOUBLE DENSITY DISKS
;
F5RMTAB:
	DEFB	00000000B	;DEBLOCK MASK
	DEFW	128		;PHYSICAL SECTOR LENGTH
	DEFB	28		;LOGICAL SECTORS PER TRACK

	DEFB	00000001B
	DEFW	256
	DEFB	18*2

	DEFB	00000011B
	DEFW	512
	DEFB	9*4

	DEFB	00000111B
	DEFW	1024
	DEFB	5*8

;
;
;	BASIC DISK PARAMS FOR DOUBLE DENSITY FORMATS
;
	DPBGEN	B8LS,D8IRSIZ	;GENERATE BSH/BLM/DIRMSK CONSTS
;

D8DSTUFF:
	DEFW	0		;NO SECTOR SKEW TABLE

	DEFW	0		;SECTORS PER TRACK (DUMMY)
	DEFB	BSHFT		;BLOCK SHIFT
	DEFB	BMASK		;BLOCK MASK
	DEFB	0		;EXTENT MASK (DUMMY)
	DEFW	0		;MAX BLOCK# (DUMMY)
	DEFW	D8IRSIZ-1	;MAX DIRECTORY ENTRY#
	DEFB	HIGH DIRMSK	;ALLOCATION MASK MSB
	DEFB	LOW DIRMSK	;ALLOCATION MASK LSB
	DEFW	D8IRSIZ/4	;CHECK VECTOR SIZE
	DEFW	R8ESERV		;RESERVED TRACKS

	DEFB	0		;DEBLOCK SHIFT COUNT (DUMMY)
	DEFB	0		;DEBLOCK MASK (DUMMY)
	DEFW	0		;BYTES PER SECTOR (DUMMY)

	DPBGEN	B5LS,D5IRSIZ

D5DSTUFF:
	DEFW	0		;NO SECTOR SKEW TABLE

	DEFW	0		;SECTORS PER TRACK (DUMMY)
	DEFB	BSHFT		;BLOCK SHIFT
	DEFB	BMASK		;BLOCK MASK
	DEFB	0		;EXTENT MASK (DUMMY)
	DEFW	0		;MAX BLOCK# (DUMMY)
	DEFW	D5IRSIZ-1	;MAX DIRECTORY ENTRY#
	DEFB	HIGH DIRMSK	;ALLOCATION MASK MSB
	DEFB	LOW DIRMSK	;ALLOCATION MASK LSB
	DEFW	D5IRSIZ/4	;CHECK VECTOR SIZE
	DEFW	R5ESERV		;RESERVED TRACKS

	DEFB	0		;DEBLOCK SHIFT COUNT (DUMMY)
	DEFB	0		;DEBLOCK MASK (DUMMY)
	DEFW	0		;BYTES PER SECTOR (DUMMY)

	ENDIF
	PAGE
;********************************************************
;*							*
;*	LOGICAL SECTOR DEBLOCKING ROUTINES FOR		*
;*	CBIOS DISK READ/WRITE FUNCTIONS			*
;*							*
;********************************************************
;
;
WRALL	EQU	0		;WRITE TO ALLOCATED
WRDIR	EQU	1		;WRITE TO DIRECTORY
WRUAL	EQU	2		;WRITE TO UNALLOCATED
;
;	INDEX OFFSETS TO ACCESS DEBLOCK PARAMETERS RELATIVE
;	TO BASE ADDRESS OF DPH ENTRY FOR SPECIFIED DRIVE
;
SPT	EQU	16
BLM	EQU	19
SHFCNT	EQU	31
SECMSK	EQU	32
SECLEN	EQU	33
FLAGS	EQU	35
;
;
;
;
READDB:
	LD	IX,(DPHPTR)	;GET POINTER TO THIS DRIVE'S PARAMETERS
	LD	A,1
	LD	(DIR),A		;SET DIRECTION FOR READ

	LD	A,(IX+SHFCNT)
	OR	A
	JR	NZ,READ1	;DO DEBLOCKING IF SECTOR LENGTH > 128

	CALL	FLUSH		;ELSE CLEAR ANY DEFERRED WRITES
	LD	A,1
	CALL	RW128		;READ 128 BYTE SECTOR DIRECTLY
	RET
;
READ1:	CALL	PHYSECT		;TRANSLATE SECTOR# TO HOST EQUIV

	LD	A,(WRTACT)
	OR	A
	JR	Z,READ2		;JUMP IF WRITE BUFFER ACTIVE

	CALL	FLUSH		;ELSE CLEAR OUT DEFERRED WRITE
	JR	READ3		; AND THEN READ NEW BUFFER FULL
;
READ2:	LD	A,(RDACT)
	OR	A
	JR	Z,READ3		;READ INTO BUFFER IF DEBLOCK INACTIVE

	CALL	HOSTCMP		;CHECK IF STILL USING SAME HOST SECTOR
	JR	Z,READ4		;GET RECORD FROM BUFFER IF STILL THERE

READ3:	LD	A,(SECTMP)	;ELSE COPY NEW DISK/TRACK/SECTOR
	LD	(HSTSEC),A	; TO HOST DISK PARAMETERS
	LD	HL,(TRACK)
	LD	(HSTTRK),HL
	LD	A,(DISK)
	LD	(HSTDSK),A
	CALL	READHST		;READ HOST SECTOR INTO DEBLOCK BUFFER
	RET	NZ		;EXIT IF DISK ERROR
READ4:	CALL	DEBLOCK		;MOVE 128 BYTES FROM BUFFER
	XOR	A
	RET			;RETURN WITH A=0 (NO ERRORS)
;
;
;
;
;
WRITEDB:
	LD	IX,(DPHPTR)	;GET POINTER TO THIS DRIVE'S PARAMETERS
	XOR	A
	LD	(DIR),A		;FLAG AS WRITE OPERATION

	LD	A,(IX+SHFCNT)
	OR	A
	JR	NZ,WRITE1	;DO DEBLOCKING FOR SECTORS > 128 BYTES

	CALL	FLUSH		;ELSE END ANY DEFERRED WRITES
	XOR	A
	CALL	RW128		;WRITE 128 BYTE SECTOR DIRECTLY
	RET
;
WRITE1:	CALL	PHYSECT		;TRANSLATE HOST EQUIV OF SECTOR#

	XOR	A
	LD	(RDACT),A	;RESET READ BUFFER ACTIVE FLAG

	LD	A,C		;WRITE TYPE IN C
	CP	WRUAL
	JR	Z,UNALOC	;JUMP IF NEW UNALLOCATED BLOCK
	CP	WRDIR
	JR	Z,ALLOC		;JUMP IF DIRECTORY WRITE
;
;	CHECK FOR CONTINUED WRITE TO UNALLOCATED BLOCK
;
	LD	A,(SECTOR)
	LD	HL,NXTSEC
	CP	(HL)
	JR	NZ,ALLOC
	LD	HL,(TRACK)
	LD	DE,(NXTTRK)
	OR	A		;COMPARE NEW SECTOR/TRACK TO PREVIOUSLY
	SBC	HL,DE		; ANTICIPATED NUMBERS FOR NEXT RECORD
	JR	NZ,ALLOC	;JUMP IF NOT IN CURRENT BLOCK

	LD	HL,RCOUNT	;CHECK IF RCOUNT HAS REACHED ZERO
	LD	A,(HL)
	OR	A
	JR	NZ,UNAL2	;JUMP IF CONTINUED WRITE

ALLOC:	CALL	FLUSH		;FINISH OLD WRITE BUSINESS
	CALL	READ3		;READ NEW BUFFER
	RET	NZ
	CALL	WRITEHST
	RET
;
;	START WRITING UNALLOCATED BLOCK BY SETTING PARAMETERS
;
UNALOC:	CALL	FLUSH		;FINISH ANY PREVIOUS DEBLOCKED WRITES
	LD	A,(IX+BLM)
	LD	(RCOUNT),A	;RCOUNT=SECTORS-PER-BLOCK MINUS 1
	LD	A,(SECTOR)
	LD	(NXTSEC),A
	LD	HL,(TRACK)	;STORE PARAMS FOR COMPUTATION OF
	LD	(NXTTRK),HL	; SUCCESSIVE SECTOR NUMBERS IN BLOCK
	JR	UNAL3
;
;	ARRIVE HERE ON SUCCESSIVE WRITES TO UNALLOCATED BLOCK
;
UNAL2:	DEC	(HL)		;RCOUNT = RCOUNT-1
	CALL	HOSTCMP		;TEST IF STILL IN SAME HOST SECTOR
	JR	Z,UNAL4		;PUT RECORD INTO BUFFER IF NOT FULL

	CALL	WRITEHST	;WRITE HOST SECTOR FROM BUFFER
	RET	NZ		;EXIT IF DISK ERROR

UNAL3:	LD	A,(SECTMP)	;ELSE COPY NEW DISK/TRACK/SECTOR
	LD	(HSTSEC),A	; TO HOST DISK PARAMETERS
	LD	HL,(TRACK)
	LD	(HSTTRK),HL
	LD	A,(DISK)
	LD	(HSTDSK),A
	LD	(HSTDPH),IX	;STORE DPH POINTER FOR CALLS TO 'FLUSH'
UNAL4:	CALL	DEBLOCK		;MOVE 128 BYTES INTO BUFFER
	LD	HL,NXTSEC
	INC	(HL)		;ADD 1 TO CURRENT DISK ADDRESS TO
	LD	A,(HL)		; GET NEXT SECTOR/TRACK NUMBER IN BLOCK
	CP	(IX+SPT)
	JR	C,UNAL5
	JR	Z,UNAL5
	LD	(HL),1		;RESET TO SECTOR# 1 AND BUMP TRACK#
	LD	HL,(NXTTRK)
	INC	HL
	LD	(NXTTRK),HL
UNAL5:	XOR	A
	RET			;RETURN WITH A=0 (NO ERRORS)
;
;
;	TRANSLATE SECTOR# TO HOST DISK EQUIVALENT
;
PHYSECT:
	LD	B,A		;LOAD B WITH SHIFT COUNT (RANGE 1..3)
	LD	A,(SECTOR)
	DEC	A		;REMOVE +1 BIAS FROM SECTOR NUMBERS
PHSEC2:	SRL	A
	DJNZ	PHSEC2
	INC	A		;REINSTATE +1 BIAS TO SECTOR#
	LD	(SECTMP),A	;SAVE FOR BUFFER RANGE TEST
	RET
;
;
;
DEBLOCK:
	LD	A,(SECTOR)
	DEC	A		;REMOVE SECTOR NUMBER +1 BIAS
	AND	(IX+SECMSK)	;MASK SECTOR# OFF TO GET BUFFER INDEX
	LD	H,0
	LD	L,A
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	LD	BC,BIGBUF
	ADD	HL,BC		;HL = HOST BUFFER ADDRESS
	LD	DE,(POINTR)	;DE = DMA ADDRESS FROM BDOS
	LD	A,(DIR)
	OR	A
	JR	NZ,DEBLK2	;SKIP IF READ
	LD	A,1
	LD	(WRTACT),A	;INDICATE BUFFERED WRITE IS ACTIVE
	EX	DE,HL		;SOURCE/DEST SWAP
DEBLK2:	LD	BC,128
	LDIR
	RET
;
;

	PAGE
;
;
HOSTCMP:
	LD	A,(SECTMP)
	LD	HL,HSTSEC
	CP	(HL)
	RET	NZ

	LD	HL,(TRACK)
	LD	DE,(HSTTRK)
	OR	A
	SBC	HL,DE
	RET	NZ

	LD	A,(DISK)
	LD	HL,HSTDSK
	CP	(HL)
	RET
;
;
;
;
FLUSH:
	XOR	A
	LD	(RDACT),A	;FLAG BUFFERED READ AS INACTIVE
	LD	(RCOUNT),A	;TERMINATE ANY WRITE TO UNALLOCATED
	LD	A,(WRTACT)
	OR	A
	RET	Z

	PUSH	IX		;SAVE CURRENT DPH POINTER IN IX
	LD	IX,(HSTDPH)	;LOAD RIGHT POINTER FOR STUFF IN BUFFER
	CALL	WRITEHST	;WRITE BUFFER ONTO HOST DISK
	POP	IX		;RESTORE DPH POINTER BEFORE GOING BACK
	RET

	IF	MIXED

;CHECK TYPE OF DISK TO SELECT, 5 1/4 OR 8 INCH.

CKTYPE:
	PUSH	BC
	LD	A,(DISK)
	INC	A		;RANGE 1-4
	LD	B,A
	LD	A,(TYPEFLAG)	;GET TYPE FROM MONITOR RAM
SKTLP:
	SRL	A		;PUT DISK FLAG IN CARRY
	DJNZ	SKTLP
	POP	BC
	RET

	ENDIF

	PAGE
;********************************************************
;*							*
;*	HOST DISK SELECT/SEEK/READ/WRITE ROUTINE	*
;*							*
;********************************************************
;
;
;
;
;
READHST:
	LD	HL,BIGBUF
	LD	(HSTPTR),HL
	LD	A,1
	LD	(RDACT),A
	CALL	DOIT		;READ SECTOR FROM DISK
	RET	Z
	LD	HL,RDACT
	LD	(HL),0		;CLEAR FLAG IF DISK READ ERROR
	RET
;
;
;
WRITEHST:
	LD	HL,BIGBUF
	LD	(HSTPTR),HL
	XOR	A
	LD	(WRTACT),A
	CALL	DOIT		;WRITE SECTOR TO DISK
	RET
;
;
;
RW128:
	LD	HL,NEW
	LD	DE,HOST
	LD	BC,6
	LDIR			;FALL THROUGH INTO 'DOIT'
;
;	... MASTER DISK READ/WRITE ROUTINE ...
;
;	CALL WITH IX POINTING TO DISK PARAMETER TABLES
;	AND ACC CONTAINING R/W OPERATION INDICATOR.
;
;
DOIT:
	LD	(RWFLAG),A	;STORE RWFLAG   1=READ  0=WRITE
	IF	WINCH
	LD	A,(HSTDSK)
	CP	NFLOPPY
	JP	NC,DOWINCH	;DO SASI DISK ROUTINE IF ON HARD DISK
	ENDIF
DOFLOP:	LD	A,(HSTDSK)
	LD	C,A
	CALL	MONITR+27	;SELECT SPECIFIED DRIVE
	JR	Z,DOFLP2
	CALL	REPORT		;REPORT SELECT ERROR TO CONSOLE
	JR	Z,DOFLOP
	RET			;RETURN PERMANENT ERROR IF NOT ZERO
;
DOFLP2:	LD	B,SIDSEL+OFF	;DEFAULT TO SELECT DISK SIDE ZERO
	LD	A,(HSTTRK)

	IF	MIXED
	LD	C,A
	CALL	CKTYPE
	LD	A,C
	JR	NC,DFLP2A
	CP	N8TRAKS
	JR	DFLP2B
DFLP2A:
	CP	N5TRAKS
DFLP2B:
	ELSE
	CP	NTRAKS		;TEST IF TRACK# IS ON OTHER SIDE
	ENDIF
	JR	C,DOFLP3
	LD	B,SIDSEL+ON	;SELECT OPPOSITE SIDE

	IF	MIXED
	LD	C,A
	CALL	CKTYPE
	LD	A,C
	JR	NC,DFLP2C
	SUB	N8TRAKS
	JR	DFLP2D
DFLP2C:
	SUB	N5TRAKS
DFLP2D:
	ELSE
	SUB	NTRAKS		;CONVERT TRACK# TO REAL VALUE
	ENDIF

DOFLP3:	LD	C,A
	LD	A,B
	OUT	(PORT0),A	;OUTPUT SIDE SELECT BIT
	CALL	MONITR+33	;SEEK SELECTED TRACK
	JR	Z,DOFLP4
	CALL	REPORT		;REPORT SEEK ERROR TO CONSOLE
	JR	Z,DOFLP2
	RET			;RETURN PERMANENT ERROR IF INDICATED
;
DOFLP4:	LD	HL,(HSTPTR)
	LD	A,(HSTSEC)
	LD	C,A
	LD	A,(RWFLAG)
	OR	A		;TEST DIRECTION   1=READ  0=WRITE
	JR	Z,DOFLP5
	CALL	MONITR+36
	JR	DOFLP6
;
DOFLP5:	CALL	MONITR+39
DOFLP6:	RET	Z		;RETURN IF READ/WRITE SUCCESSFUL
	CALL	REPORT
	JR	Z,DOFLP4	;TRY AGAIN IF INDICATED
	RET
;
;
;
;
REPORT:	LD	E,A		;SAVE PERTINENT ERROR BITS IN E
	LD	A,(HSTDSK)
	ADD	A,'A'
	LD	(DSKMSG+16),A
	LD	HL,DSKMSG
	CALL	PMSG		;PRINT OUT START OF MESSAGE
	LD	BC,08FFH	;B=LOOPCOUNT   C=255 FOR CPIR SCAN
	LD	A,E
REP2:	RLA
	JR	C,REP3
	PUSH	AF
	XOR	A
	CPIR			;SCAN MEMORY LOOKING FOR NULL
	POP	AF
	DJNZ	REP2
REP3:	CALL	PMSG		;PRINT ERROR TYPE STRING
	LD	A,E
	AND	11000000B	;MASK TO NOT-READY AND WRITE-PROTECT
	JR	NZ,REP5

	LD	HL,TSMSG
	CALL	PMSG
	LD	A,(HSTTRK)
	CALL	PUTDEC
	CALL	PMSG
	LD	A,(HSTSEC)
	CALL	PUTDEC
	LD	A,1
	OR	A
	RET
;
REP5:	LD	HL,PROMPT
	CALL	PMSG
	CALL	IVEC		;LOOP FOR CONSOLE INPUT
	CP	'C'-64
	JR	Z,REP6
	XOR	A
	RET
;
REP6:	XOR	A
	LD	(IOBYTE+1),A	;CLEAR AUTO-LOG BYTE IF CTL-C ABORT
	INC	A
	RET			;RETURN PERMANENT BIOS ERROR
;
;
;
;	CHARACTER STRING OUTPUT ROUTINE. PRINTS ASCII DATA
;	POINTED TO BY HL UNTIL A DOLLAR SIGN IS ENCOUNTERED
;
PMSG:	LD	A,(HL)		;HL POINTS TO ASCII STRING
	INC	HL
	OR	A		;TEST FOR BYTE EQUAL ZERO
	RET	Z
	LD	C,A		;PRINT CHARACTER IF NOT DOLLAR SIGN
	CALL	OVEC
	JR	PMSG
;
;
;
;	PRINT CONTENTS OF A IN DECIMAL (RANGE 0..255)
;
PUTDEC:
	LD	B,100
	CALL	PDIGIT		;PRINT HUNDREDS DIGIT
	LD	B,10
	CALL	PDIGIT		;PRINT TENS DIGIT
PNUM:	OR	'0'
	LD	C,A
	CALL	OVEC
	RET
;
;
PDIGIT:
	LD	C,-1
PDIG1:	INC	C
	SUB	B
	JR	NC,PDIG1
	ADD	A,B
	PUSH	AF
	LD	A,C
	OR	A
	CALL	NZ,PNUM		;PRINT NUMERIC CHARACTER IF NON-ZERO
	POP	AF
	RET
;
;
;
;
;
;	
NULL	EQU	00H		;NULL (END-OF-STRING INDICATOR)
LF	EQU	0AH		;LINE FEED
CR	EQU	0DH		;CARRIAGE RETURN
	
DSKMSG:	DEFB	CR,LF
	DEFB	'BIOS error on A:  ',NULL

	DEFB	'not ready',NULL
	DEFB	'wrt protect',NULL
	DEFB	'wrt fault',NULL
	DEFB	'not found',NULL
	DEFB	'bad crc',NULL
	DEFB	'overrun',NULL
	DEFB	'drq',NULL
	DEFB	'busy',NULL
	DEFB	NULL

TSMSG:	DEFB	'  track ',NULL
	DEFB	'  sector ',NULL

PROMPT:	DEFB	' ?','H'-64,NULL
;
;
;
;
;
